aboutsummaryrefslogtreecommitdiff
path: root/guilib
diff options
context:
space:
mode:
authorAlTheKiller <AlTheKiller@svn>2009-09-23 01:49:50 +0000
committerAlTheKiller <AlTheKiller@svn>2009-09-23 01:49:50 +0000
commit45285e8a9300cd754a760560640b75b09f98035e (patch)
treead9f093885ad5c98e9dd4156674e7691c22ed0a2 /guilib
step 3/4: Move linuxport to trunk. How'd I get roped into this?
git-svn-id: https://xbmc.svn.sourceforge.net/svnroot/xbmc/trunk@23097 568bbfeb-2a22-0410-94d2-cc84cf5bfa90
Diffstat (limited to 'guilib')
-rw-r--r--guilib/AnimatedGif.cpp648
-rw-r--r--guilib/AnimatedGif.h162
-rw-r--r--guilib/AudioContext.cpp277
-rw-r--r--guilib/AudioContext.h79
-rw-r--r--guilib/DirectXGraphics.cpp458
-rw-r--r--guilib/DirectXGraphics.h176
-rw-r--r--guilib/FrameBufferObject.cpp134
-rw-r--r--guilib/FrameBufferObject.h111
-rw-r--r--guilib/GUIActionDescriptor.h36
-rw-r--r--guilib/GUIAudioManager.cpp445
-rw-r--r--guilib/GUIAudioManager.h88
-rw-r--r--guilib/GUIBaseContainer.cpp1183
-rw-r--r--guilib/GUIBaseContainer.h181
-rw-r--r--guilib/GUIBorderedImage.cpp73
-rw-r--r--guilib/GUIBorderedImage.h47
-rw-r--r--guilib/GUIButtonControl.cpp331
-rw-r--r--guilib/GUIButtonControl.h103
-rw-r--r--guilib/GUIButtonScroller.cpp951
-rw-r--r--guilib/GUIButtonScroller.h128
-rw-r--r--guilib/GUICallback.h193
-rw-r--r--guilib/GUICheckMarkControl.cpp174
-rw-r--r--guilib/GUICheckMarkControl.h74
-rw-r--r--guilib/GUIColorManager.cpp116
-rw-r--r--guilib/GUIColorManager.h70
-rw-r--r--guilib/GUIControl.cpp887
-rw-r--r--guilib/GUIControl.h317
-rw-r--r--guilib/GUIControlFactory.cpp1415
-rw-r--r--guilib/GUIControlFactory.h77
-rw-r--r--guilib/GUIControlGroup.cpp631
-rw-r--r--guilib/GUIControlGroup.h113
-rw-r--r--guilib/GUIControlGroupList.cpp405
-rw-r--r--guilib/GUIControlGroupList.h74
-rw-r--r--guilib/GUIControlProfiler.cpp368
-rw-r--r--guilib/GUIControlProfiler.h102
-rw-r--r--guilib/GUIDialog.cpp256
-rw-r--r--guilib/GUIDialog.h73
-rw-r--r--guilib/GUIEditControl.cpp482
-rw-r--r--guilib/GUIEditControl.h100
-rw-r--r--guilib/GUIFadeLabelControl.cpp229
-rw-r--r--guilib/GUIFadeLabelControl.h75
-rw-r--r--guilib/GUIFixedListContainer.cpp249
-rw-r--r--guilib/GUIFixedListContainer.h56
-rw-r--r--guilib/GUIFont.cpp272
-rw-r--r--guilib/GUIFont.h142
-rw-r--r--guilib/GUIFontManager.cpp484
-rw-r--r--guilib/GUIFontManager.h89
-rw-r--r--guilib/GUIFontTTF.cpp772
-rw-r--r--guilib/GUIFontTTF.h182
-rw-r--r--guilib/GUIFontTTFDX.cpp196
-rw-r--r--guilib/GUIFontTTFDX.h55
-rw-r--r--guilib/GUIFontTTFGL.cpp210
-rw-r--r--guilib/GUIFontTTFGL.h56
-rw-r--r--guilib/GUIFontTTFGLES.cpp82
-rw-r--r--guilib/GUIFontTTFGLES.h56
-rw-r--r--guilib/GUIImage.cpp343
-rw-r--r--guilib/GUIImage.h119
-rw-r--r--guilib/GUIIncludes.cpp196
-rw-r--r--guilib/GUIIncludes.h51
-rw-r--r--guilib/GUIInfoColor.cpp107
-rw-r--r--guilib/GUIInfoColor.h69
-rw-r--r--guilib/GUILabelControl.cpp424
-rw-r--r--guilib/GUILabelControl.h118
-rw-r--r--guilib/GUIListContainer.cpp275
-rw-r--r--guilib/GUIListContainer.h62
-rw-r--r--guilib/GUIListGroup.cpp211
-rw-r--r--guilib/GUIListGroup.h60
-rw-r--r--guilib/GUIListItem.cpp382
-rw-r--r--guilib/GUIListItem.h150
-rw-r--r--guilib/GUIListItemLayout.cpp197
-rw-r--r--guilib/GUIListItemLayout.h71
-rw-r--r--guilib/GUIListLabel.cpp130
-rw-r--r--guilib/GUIListLabel.h70
-rw-r--r--guilib/GUIMessage.cpp195
-rw-r--r--guilib/GUIMessage.h288
-rw-r--r--guilib/GUIMoverControl.cpp244
-rw-r--r--guilib/GUIMoverControl.h97
-rw-r--r--guilib/GUIMultiImage.cpp246
-rw-r--r--guilib/GUIMultiImage.h79
-rw-r--r--guilib/GUIMultiSelectText.cpp439
-rw-r--r--guilib/GUIMultiSelectText.h102
-rw-r--r--guilib/GUIPanelContainer.cpp482
-rw-r--r--guilib/GUIPanelContainer.h69
-rw-r--r--guilib/GUIProgressControl.cpp260
-rw-r--r--guilib/GUIProgressControl.h77
-rw-r--r--guilib/GUIRSSControl.cpp145
-rw-r--r--guilib/GUIRSSControl.h87
-rw-r--r--guilib/GUIRadioButtonControl.cpp152
-rw-r--r--guilib/GUIRadioButtonControl.h68
-rw-r--r--guilib/GUIResizeControl.cpp225
-rw-r--r--guilib/GUIResizeControl.h85
-rw-r--r--guilib/GUIScrollBarControl.cpp310
-rw-r--r--guilib/GUIScrollBarControl.h86
-rw-r--r--guilib/GUISelectButtonControl.cpp404
-rw-r--r--guilib/GUISelectButtonControl.h134
-rw-r--r--guilib/GUISettingsSliderControl.cpp116
-rw-r--r--guilib/GUISettingsSliderControl.h73
-rw-r--r--guilib/GUISliderControl.cpp362
-rw-r--r--guilib/GUISliderControl.h98
-rw-r--r--guilib/GUISound.cpp274
-rw-r--r--guilib/GUISound.h55
-rw-r--r--guilib/GUISpinControl.cpp939
-rw-r--r--guilib/GUISpinControl.h127
-rw-r--r--guilib/GUISpinControlEx.cpp134
-rw-r--r--guilib/GUISpinControlEx.h72
-rw-r--r--guilib/GUIStandardWindow.cpp50
-rw-r--r--guilib/GUIStandardWindow.h39
-rw-r--r--guilib/GUITextBox.cpp347
-rw-r--r--guilib/GUITextBox.h96
-rw-r--r--guilib/GUITextLayout.cpp635
-rw-r--r--guilib/GUITextLayout.h132
-rw-r--r--guilib/GUITexture.cpp600
-rw-r--r--guilib/GUITexture.h215
-rw-r--r--guilib/GUITextureD3D.cpp224
-rw-r--r--guilib/GUITextureD3D.h49
-rw-r--r--guilib/GUITextureGL.cpp189
-rw-r--r--guilib/GUITextureGL.h45
-rw-r--r--guilib/GUITextureGLES.cpp54
-rw-r--r--guilib/GUITextureGLES.h45
-rw-r--r--guilib/GUITextureSDL.cpp209
-rw-r--r--guilib/GUITextureSDL.h67
-rw-r--r--guilib/GUIToggleButtonControl.cpp152
-rw-r--r--guilib/GUIToggleButtonControl.h66
-rw-r--r--guilib/GUIVideoControl.cpp116
-rw-r--r--guilib/GUIVideoControl.h52
-rw-r--r--guilib/GUIVisualisationControl.cpp484
-rw-r--r--guilib/GUIVisualisationControl.h88
-rw-r--r--guilib/GUIWindow.cpp1022
-rw-r--r--guilib/GUIWindow.h243
-rw-r--r--guilib/GUIWindowManager.cpp891
-rw-r--r--guilib/GUIWindowManager.h142
-rw-r--r--guilib/GUIWrappingListContainer.cpp255
-rw-r--r--guilib/GUIWrappingListContainer.h62
-rw-r--r--guilib/Geometry.h149
-rw-r--r--guilib/GraphicContext.cpp797
-rw-r--r--guilib/GraphicContext.h206
-rw-r--r--guilib/IAudioDeviceChangedCallback.h31
-rw-r--r--guilib/IMsgSenderCallback.h45
-rw-r--r--guilib/IMsgTargetCallback.h45
-rw-r--r--guilib/IWindowManagerCallback.cpp29
-rw-r--r--guilib/IWindowManagerCallback.h42
-rw-r--r--guilib/Key.cpp165
-rw-r--r--guilib/Key.h460
-rw-r--r--guilib/LocalizeStrings.cpp229
-rw-r--r--guilib/LocalizeStrings.h72
-rw-r--r--guilib/Makefile87
-rw-r--r--guilib/Resolution.h99
-rw-r--r--guilib/Shader.cpp534
-rw-r--r--guilib/Shader.h263
-rw-r--r--guilib/SkinInfo.cpp409
-rw-r--r--guilib/SkinInfo.h95
-rw-r--r--guilib/StdString.h4335
-rw-r--r--guilib/Texture.cpp177
-rw-r--r--guilib/Texture.h96
-rw-r--r--guilib/TextureBundle.cpp492
-rw-r--r--guilib/TextureBundle.h70
-rw-r--r--guilib/TextureDX.cpp105
-rw-r--r--guilib/TextureDX.h52
-rw-r--r--guilib/TextureGL.cpp116
-rw-r--r--guilib/TextureGL.h52
-rw-r--r--guilib/TextureManager.cpp579
-rw-r--r--guilib/TextureManager.h140
-rw-r--r--guilib/TransformMatrix.h240
-rw-r--r--guilib/Tween.h408
-rw-r--r--guilib/VisibleEffect.cpp703
-rw-r--r--guilib/VisibleEffect.h205
-rw-r--r--guilib/XMLUtils.cpp254
-rw-r--r--guilib/XMLUtils.h54
-rw-r--r--guilib/common/IRServerSuite/IRServerSuite.cpp449
-rw-r--r--guilib/common/IRServerSuite/IRServerSuite.h64
-rw-r--r--guilib/common/IRServerSuite/IrssMessage.cpp146
-rw-r--r--guilib/common/IRServerSuite/IrssMessage.h209
-rw-r--r--guilib/common/LIRC.cpp257
-rw-r--r--guilib/common/LIRC.h44
-rw-r--r--guilib/common/Makefile.in14
-rw-r--r--guilib/common/SDLJoystick.cpp388
-rw-r--r--guilib/common/SDLJoystick.h78
-rw-r--r--guilib/freetype2/freetype239ST.libbin0 -> 876844 bytes
-rw-r--r--guilib/freetype2/freetype239ST_D.libbin0 -> 2235620 bytes
-rw-r--r--guilib/freetype2/include/freetype/config/ftconfig.h500
-rw-r--r--guilib/freetype2/include/freetype/config/ftheader.h780
-rw-r--r--guilib/freetype2/include/freetype/config/ftoption.h693
-rw-r--r--guilib/freetype2/include/freetype/config/ftstdlib.h172
-rw-r--r--guilib/freetype2/include/freetype/freetype.h3862
-rw-r--r--guilib/freetype2/include/freetype/ftcache.h1125
-rw-r--r--guilib/freetype2/include/freetype/fterrdef.h239
-rw-r--r--guilib/freetype2/include/freetype/fterrors.h206
-rw-r--r--guilib/freetype2/include/freetype/ftglyph.h613
-rw-r--r--guilib/freetype2/include/freetype/ftimage.h1254
-rw-r--r--guilib/freetype2/include/freetype/ftmoderr.h155
-rw-r--r--guilib/freetype2/include/freetype/ftoutln.h538
-rw-r--r--guilib/freetype2/include/freetype/ftsystem.h346
-rw-r--r--guilib/freetype2/include/freetype/fttypes.h587
-rw-r--r--guilib/freetype2/include/ft2build.h39
-rw-r--r--guilib/gui3d.h107
-rw-r--r--guilib/guilib_win32.vcproj772
-rw-r--r--guilib/system.h191
-rw-r--r--guilib/tinyXML/Makefile6
-rw-r--r--guilib/tinyXML/tinystr.cpp116
-rw-r--r--guilib/tinyXML/tinystr.h319
-rw-r--r--guilib/tinyXML/tinyxml.cpp2066
-rw-r--r--guilib/tinyXML/tinyxml.h1830
-rw-r--r--guilib/tinyXML/tinyxmlerror.cpp53
-rw-r--r--guilib/tinyXML/tinyxmlparser.cpp1683
203 files changed, 62607 insertions, 0 deletions
diff --git a/guilib/AnimatedGif.cpp b/guilib/AnimatedGif.cpp
new file mode 100644
index 0000000000..d1c5f6be2b
--- /dev/null
+++ b/guilib/AnimatedGif.cpp
@@ -0,0 +1,648 @@
+
+// ****************************************************************************
+//
+// WINIMAGE.CPP : Generic classes for raster images (MSWindows specialization)
+//
+// Content: Member definitions for:
+// - class CAnimatedGif : Storage class for single images
+// - class CAnimatedGifSet : Storage class for sets of images
+//
+// (Includes routines to Load and Save BMP files and to load GIF files into
+// these classes).
+//
+// --------------------------------------------------------------------------
+//
+// Copyright (c) 2000, Juan Soulie <jsoulie@cplusplus.com>
+//
+// Permission to use, copy, modify, distribute and sell this software or any
+// part thereof and/or its documentation for any purpose is granted without fee
+// provided that the above copyright notice and this permission notice appear
+// in all copies.
+//
+// This software is provided "as is" without express or implied warranty of
+// any kind. The author shall have no liability with respect to the
+// infringement of copyrights or patents that any modification to the content
+// of this file or this file itself may incur.
+//
+// ****************************************************************************
+
+#include "AnimatedGif.h"
+#include "FileSystem/SpecialProtocol.h"
+#include "utils/EndianSwap.h"
+
+#ifdef _WIN32PC
+extern "C" FILE *fopen_utf8(const char *_Filename, const char *_Mode);
+#else
+#define fopen_utf8 fopen
+#endif
+
+#pragma pack(1)
+// Error processing macro (NO-OP by default):
+#define ERRORMSG(PARAM) {}
+
+#ifndef BI_RGB
+ #define BI_RGB 0L
+ #define BI_RLE8 1L
+ #define BI_RLE4 2L
+ #define BI_BITFIELDS 3L
+#endif
+
+// Macros to swap data endianness
+#define SWAP16(X) X=Endian_SwapLE16(X)
+#define SWAP32(X) X=Endian_SwapLE32(X)
+
+// pre-declaration:
+int LZWDecoder (char*, char*, short, int, int, int, const int);
+
+// ****************************************************************************
+// * CAnimatedGif Member definitions *
+// ****************************************************************************
+
+CAnimatedGif::CAnimatedGif()
+{
+ Height = Width = 0;
+ Raster = NULL;
+ Palette = NULL;
+ pbmi = NULL;
+ BPP = Transparent = BytesPerRow = 0;
+ xPos = yPos = Delay = Transparency = 0;
+ nLoops = 1; //default=play animation 1 time
+}
+
+CAnimatedGif::~CAnimatedGif()
+{
+ delete [] pbmi;
+ delete [] Raster;
+ delete [] Palette;
+}
+
+// Init: Allocates space for raster and palette in GDI-compatible structures.
+void CAnimatedGif::Init(int iWidth, int iHeight, int iBPP, int iLoops)
+{
+ delete[] Raster;
+ Raster = NULL;
+
+ delete[] pbmi;
+ pbmi = NULL;
+
+ delete[] Palette;
+ Palette = NULL;
+
+ // Standard members setup
+ Transparent = -1;
+ BytesPerRow = Width = iWidth;
+ Height = iHeight;
+ BPP = iBPP;
+ // Animation Extra members setup:
+ xPos = yPos = Delay = Transparency = 0;
+ nLoops = iLoops;
+
+ if (BPP == 24)
+ {
+ BytesPerRow *= 3;
+ pbmi = (GUIBITMAPINFO*)new char [sizeof(GUIBITMAPINFO)];
+ }
+ else
+ {
+ pbmi = (GUIBITMAPINFO*)new char[sizeof(GUIBITMAPINFOHEADER)];
+ Palette = new COLOR[256];
+ }
+
+ BytesPerRow += (ALIGN - Width % ALIGN) % ALIGN; // Align BytesPerRow
+ int size = BytesPerRow * Height;
+
+ Raster = new char [size];
+
+ pbmi->bmiHeader.biSize = sizeof (GUIBITMAPINFOHEADER);
+ pbmi->bmiHeader.biWidth = Width;
+ pbmi->bmiHeader.biHeight = -Height; // negative means up-to-bottom
+ pbmi->bmiHeader.biPlanes = 1;
+ pbmi->bmiHeader.biBitCount = (BPP < 8 ? 8 : BPP); // Our raster is byte-aligned
+ pbmi->bmiHeader.biCompression = BI_RGB;
+ pbmi->bmiHeader.biSizeImage = 0;
+ pbmi->bmiHeader.biXPelsPerMeter = 11811;
+ pbmi->bmiHeader.biYPelsPerMeter = 11811;
+ pbmi->bmiHeader.biClrUsed = 0;
+ pbmi->bmiHeader.biClrImportant = 0;
+}
+
+// operator=: copies an object's content to another
+CAnimatedGif& CAnimatedGif::operator = (CAnimatedGif& rhs)
+{
+ Init(rhs.Width, rhs.Height, rhs.BPP); // respects virtualization
+ memcpy(Raster, rhs.Raster, BytesPerRow*Height);
+ memcpy(Palette, rhs.Palette, 256*sizeof(COLOR));
+ return *this;
+}
+
+
+
+CAnimatedGifSet::CAnimatedGifSet()
+{
+ FrameHeight = FrameWidth = 0;
+ nLoops = 1; //default=play animation 1 time
+}
+
+CAnimatedGifSet::~CAnimatedGifSet()
+{
+ Release();
+}
+
+void CAnimatedGifSet::Release()
+{
+ FrameWidth = 0;
+ FrameHeight = 0;
+ for (int i = 0; i < (int)m_vecimg.size(); ++i)
+ {
+ CAnimatedGif* pImage = m_vecimg[i];
+ delete pImage;
+ }
+ m_vecimg.erase(m_vecimg.begin(), m_vecimg.end());
+
+}
+
+// ****************************************************************************
+// * CAnimatedGifSet Member definitions *
+// ****************************************************************************
+
+// AddImage: Adds an image object to the back of the img vector.
+void CAnimatedGifSet::AddImage (CAnimatedGif* newimage)
+{
+ m_vecimg.push_back(newimage);
+}
+
+int CAnimatedGifSet::GetImageCount() const
+{
+ return m_vecimg.size();
+}
+
+unsigned char CAnimatedGifSet::getbyte(FILE *fd)
+{
+ unsigned char uchar;
+ if (fread(&uchar, 1, 1, fd) == 1)
+ return uchar;
+ else
+ return 0;
+}
+
+// ****************************************************************************
+// * LoadGIF *
+// * Load a GIF File into the CAnimatedGifSet object *
+// * (c) Nov 2000, Juan Soulie <jsoulie@cplusplus.com> *
+// ****************************************************************************
+int CAnimatedGifSet::LoadGIF (const char * szFileName)
+{
+ int n;
+ // Global GIF variables:
+ int GlobalBPP; // Bits per Pixel.
+ COLOR * GlobalColorMap; // Global colormap (allocate)
+
+ struct GIFGCEtag
+ { // GRAPHIC CONTROL EXTENSION
+ unsigned char BlockSize; // Block Size: 4 bytes
+ unsigned char PackedFields; // 3.. Packed Fields. Bits detail:
+ // 0: Transparent Color Flag
+ // 1: User Input Flag
+ // 2-4: Disposal Method
+ unsigned short Delay; // 4..5 Delay Time (1/100 seconds)
+ unsigned char Transparent; // 6.. Transparent Color Index
+ }
+ gifgce;
+
+ struct GIFNetscapeTag
+ {
+ unsigned char comment[11]; //4...14 NETSCAPE2.0
+ unsigned char SubBlockLength; //15 0x3
+ unsigned char reserved; //16 0x1
+ unsigned short iIterations ; //17..18 number of iterations (lo-hi)
+ }
+ gifnetscape;
+
+ int GraphicExtensionFound = 0;
+
+ // OPEN FILE
+ FILE *fd = fopen_utf8(_P(szFileName), "rb");
+ if (!fd)
+ {
+ return 0;
+ }
+
+ // *1* READ HEADERBLOCK (6bytes) (SIGNATURE + VERSION)
+ char szSignature[6]; // First 6 bytes (GIF87a or GIF89a)
+ int iRead = fread(szSignature, 1, 6, fd);
+ if (iRead != 6)
+ {
+ fclose(fd);
+ return 0;
+ }
+ if ( memcmp(szSignature, "GIF", 2) != 0)
+ {
+ fclose(fd);
+ return 0;
+ }
+ // *2* READ LOGICAL SCREEN DESCRIPTOR
+ struct GIFLSDtag
+ {
+ unsigned short ScreenWidth; // Logical Screen Width
+ unsigned short ScreenHeight; // Logical Screen Height
+ unsigned char PackedFields; // Packed Fields. Bits detail:
+ // 0-2: Size of Global Color Table
+ // 3: Sort Flag
+ // 4-6: Color Resolution
+ // 7: Global Color Table Flag
+ unsigned char Background; // Background Color Index
+ unsigned char PixelAspectRatio; // Pixel Aspect Ratio
+ }
+ giflsd;
+
+ iRead = fread(&giflsd, 1, sizeof(giflsd), fd);
+ if (iRead != sizeof(giflsd))
+ {
+ fclose(fd);
+ return 0;
+ }
+ // endian swap
+ SWAP16(giflsd.ScreenWidth);
+ SWAP16(giflsd.ScreenHeight);
+
+ GlobalBPP = (giflsd.PackedFields & 0x07) + 1;
+
+ // fill some animation data:
+ FrameWidth = giflsd.ScreenWidth;
+ FrameHeight = giflsd.ScreenHeight;
+ nLoops = 1; //default=play animation 1 time
+
+ // *3* READ/GENERATE GLOBAL COLOR MAP
+ GlobalColorMap = new COLOR [1 << GlobalBPP];
+ if (giflsd.PackedFields & 0x80) // File has global color map?
+ for (n = 0;n < 1 << GlobalBPP;n++)
+ {
+ GlobalColorMap[n].r = getbyte(fd);
+ GlobalColorMap[n].g = getbyte(fd);
+ GlobalColorMap[n].b = getbyte(fd);
+ }
+
+ else // GIF standard says to provide an internal default Palette:
+ for (n = 0;n < 256;n++)
+ GlobalColorMap[n].r = GlobalColorMap[n].g = GlobalColorMap[n].b = n;
+
+ // *4* NOW WE HAVE 3 POSSIBILITIES:
+ // 4a) Get and Extension Block (Blocks with additional information)
+ // 4b) Get an Image Separator (Introductor to an image)
+ // 4c) Get the trailer Char (End of GIF File)
+ do
+ {
+ int charGot = getbyte(fd);
+
+ if (charGot == 0x21) // *A* EXTENSION BLOCK
+ {
+ unsigned char extensionType = getbyte(fd);
+ switch (extensionType)
+ {
+ case 0xF9: // Graphic Control Extension
+ {
+ if (fread((char*)&gifgce, 1, sizeof(gifgce), fd) == sizeof(gifgce))
+ SWAP16(gifgce.Delay);
+ GraphicExtensionFound++;
+ getbyte(fd); // Block Terminator (always 0)
+ }
+ break;
+
+ case 0xFE: // Comment Extension: Ignored
+ {
+ while (int nBlockLength = getbyte(fd))
+ for (n = 0;n < nBlockLength;n++) getbyte(fd);
+ }
+ break;
+
+ case 0x01: // PlainText Extension: Ignored
+ {
+ while (int nBlockLength = getbyte(fd))
+ for (n = 0;n < nBlockLength;n++) getbyte(fd);
+ }
+ break;
+
+ case 0xFF: // Application Extension: Ignored
+ {
+ int nBlockLength = getbyte(fd);
+ if (nBlockLength == 0x0b)
+ {
+ struct GIFNetscapeTag tag;
+ if (fread((char*)&tag, 1, sizeof(gifnetscape), fd) == sizeof(gifnetscape))
+ {
+ SWAP16(tag.iIterations);
+ nLoops = tag.iIterations;
+ }
+ else
+ nLoops = 0;
+
+ if (nLoops) nLoops++;
+ getbyte(fd);
+ }
+ else
+ {
+ do
+ {
+ for (n = 0;n < nBlockLength;n++) getbyte(fd);
+ }
+ while ((nBlockLength = getbyte(fd)) != 0);
+ }
+ }
+ break;
+
+ default: // Unknown Extension: Ignored
+ {
+ // read (and ignore) data sub-blocks
+ while (int nBlockLength = getbyte(fd))
+ for (n = 0;n < nBlockLength;n++) getbyte(fd);
+ }
+ break;
+ }
+ }
+ else if (charGot == 0x2c)
+ { // *B* IMAGE (0x2c Image Separator)
+ // Create a new Image Object:
+ CAnimatedGif* NextImage = new CAnimatedGif();
+
+ // Read Image Descriptor
+ struct GIFIDtag
+ {
+ unsigned short xPos; // Image Left Position
+ unsigned short yPos; // Image Top Position
+ unsigned short Width; // Image Width
+ unsigned short Height; // Image Height
+ unsigned char PackedFields; // Packed Fields. Bits detail:
+ // 0-2: Size of Local Color Table
+ // 3-4: (Reserved)
+ // 5: Sort Flag
+ // 6: Interlace Flag
+ // 7: Local Color Table Flag
+ }
+ gifid;
+
+ memset(&gifid, 0, sizeof(gifid));
+
+ int LocalColorMap = 0;
+ if (fread((char*)&gifid, 1, sizeof(gifid), fd) == sizeof(gifid))
+ {
+ SWAP16(gifid.xPos);
+ SWAP16(gifid.yPos);
+ SWAP16(gifid.Width);
+ SWAP16(gifid.Height);
+
+ LocalColorMap = (gifid.PackedFields & 0x08) ? 1 : 0;
+ }
+
+ NextImage->Init(gifid.Width, gifid.Height, LocalColorMap ? (gifid.PackedFields&7) + 1 : GlobalBPP);
+
+ // Fill NextImage Data
+ NextImage->xPos = gifid.xPos;
+ NextImage->yPos = gifid.yPos;
+ if (GraphicExtensionFound)
+ {
+ NextImage->Transparent = (gifgce.PackedFields & 0x01) ? gifgce.Transparent : -1;
+ NextImage->Transparency = (gifgce.PackedFields & 0x1c) > 1 ? 1 : 0;
+ NextImage->Delay = gifgce.Delay * 10;
+ }
+
+ if (NextImage->Transparent != -1)
+ memset(NextImage->Raster, NextImage->Transparent, NextImage->BytesPerRow * NextImage->Height);
+ else
+ memset(NextImage->Raster, giflsd.Background, NextImage->BytesPerRow * NextImage->Height);
+
+ // Read Color Map (if descriptor says so)
+ size_t palSize = sizeof(COLOR)*(1 << NextImage->BPP);
+ bool isPalRead = false;
+ if (LocalColorMap && fread((char*)NextImage->Palette, 1, palSize, fd) == palSize)
+ isPalRead = true;
+
+ // Copy global, if no palette
+ if (!isPalRead)
+ memcpy(NextImage->Palette, GlobalColorMap, palSize);
+
+ short firstbyte = getbyte(fd); // 1st byte of img block (CodeSize)
+
+ // Calculate compressed image block size
+ // to fix: this allocates an extra byte per block
+ long ImgStart, ImgEnd;
+ ImgEnd = ImgStart = ftell(fd);
+ while ((n = getbyte(fd)) != 0) fseek (fd, ImgEnd += n + 1, SEEK_SET );
+ fseek (fd, ImgStart, SEEK_SET);
+
+ // Allocate Space for Compressed Image
+ char * pCompressedImage = new char [ImgEnd - ImgStart + 4];
+
+ // Read and store Compressed Image
+ char * pTemp = pCompressedImage;
+ while (int nBlockLength = getbyte(fd))
+ {
+ if (fread(pTemp, 1, nBlockLength, fd) != (size_t)nBlockLength)
+ {
+ // Error?
+ }
+ pTemp += nBlockLength;
+ }
+
+ // Call LZW/GIF decompressor
+ n = LZWDecoder(
+ (char*) pCompressedImage,
+ (char*) NextImage->Raster,
+ firstbyte, NextImage->BytesPerRow, //NextImage->AlignedWidth,
+ gifid.Width, gifid.Height,
+ ((gifid.PackedFields & 0x40) ? 1 : 0) //Interlaced?
+ );
+
+ if (n)
+ AddImage(NextImage);
+ else
+ {
+ delete NextImage;
+ ERRORMSG("GIF File Corrupt");
+ }
+
+ // Some cleanup
+ delete[] pCompressedImage;
+ GraphicExtensionFound = 0;
+ }
+ else if (charGot == 0x3b)
+ {
+ // *C* TRAILER: End of GIF Info
+ break; // Ok. Standard End.
+ }
+
+ }
+ while ( !feof(fd) );
+
+ delete[] GlobalColorMap;
+ fclose(fd);
+ if ( GetImageCount() == 0) ERRORMSG("Premature End Of File");
+ return GetImageCount();
+}
+
+// ****************************************************************************
+// * LZWDecoder (C/C++) *
+// * Codec to perform LZW (GIF Variant) decompression. *
+// * (c) Nov2000, Juan Soulie <jsoulie@cplusplus.com> *
+// ****************************************************************************
+//
+// Parameter description:
+// - bufIn: Input buffer containing a "de-blocked" GIF/LZW compressed image.
+// - bufOut: Output buffer where result will be stored.
+// - InitCodeSize: Initial CodeSize to be Used
+// (GIF files include this as the first byte in a picture block)
+// - AlignedWidth : Width of a row in memory (including alignment if needed)
+// - Width, Height: Physical dimensions of image.
+// - Interlace: 1 for Interlaced GIFs.
+//
+int LZWDecoder (char * bufIn, char * bufOut,
+ short InitCodeSize, int AlignedWidth,
+ int Width, int Height, const int Interlace)
+{
+ int n;
+ int row = 0, col = 0; // used to point output if Interlaced
+ int nPixels, maxPixels; // Output pixel counter
+
+ short CodeSize; // Current CodeSize (size in bits of codes)
+ short ClearCode; // Clear code : resets decompressor
+ short EndCode; // End code : marks end of information
+
+ long whichBit; // Index of next bit in bufIn
+ long LongCode; // Temp. var. from which Code is retrieved
+ short Code; // Code extracted
+ short PrevCode; // Previous Code
+ short OutCode; // Code to output
+
+ // Translation Table:
+ short Prefix[4096]; // Prefix: index of another Code
+ unsigned char Suffix[4096]; // Suffix: terminating character
+ short FirstEntry; // Index of first free entry in table
+ short NextEntry; // Index of next free entry in table
+
+ unsigned char OutStack[4097]; // Output buffer
+ int OutIndex; // Characters in OutStack
+
+ int RowOffset; // Offset in output buffer for current row
+
+ // Set up values that depend on InitCodeSize Parameter.
+ CodeSize = InitCodeSize + 1;
+ ClearCode = (1 << InitCodeSize);
+ EndCode = ClearCode + 1;
+ NextEntry = FirstEntry = ClearCode + 2;
+
+ whichBit = 0;
+ nPixels = 0;
+ maxPixels = Width * Height;
+ RowOffset = 0;
+ PrevCode = 0;
+
+ while (nPixels < maxPixels)
+ {
+ OutIndex = 0; // Reset Output Stack
+
+ // GET NEXT CODE FROM bufIn:
+ // LZW compression uses code items longer than a single byte.
+ // For GIF Files, code sizes are variable between 9 and 12 bits
+ // That's why we must read data (Code) this way:
+ LongCode = *((long*)(bufIn + whichBit / 8)); // Get some bytes from bufIn
+ SWAP32(LongCode);
+ LongCode >>= (whichBit&7); // Discard too low bits
+ Code = (short)((LongCode & ((1 << CodeSize) - 1) )); // Discard too high bits
+ whichBit += CodeSize; // Increase Bit Offset
+
+ // SWITCH, DIFFERENT POSIBILITIES FOR CODE:
+ if (Code == EndCode) // END CODE
+ break; // Exit LZW Decompression loop
+
+ if (Code == ClearCode)
+ {
+ // CLEAR CODE:
+ CodeSize = InitCodeSize + 1; // Reset CodeSize
+ NextEntry = FirstEntry; // Reset Translation Table
+ PrevCode = Code; // Prevent next to be added to table.
+ continue; // restart, to get another code
+ }
+ if (Code < NextEntry) // CODE IS IN TABLE
+ OutCode = Code; // Set code to output.
+
+ else
+ { // CODE IS NOT IN TABLE:
+ OutIndex++; // Keep "first" character of previous output.
+ OutCode = PrevCode; // Set PrevCode to be output
+ }
+
+ // EXPAND OutCode IN OutStack
+ // - Elements up to FirstEntry are Raw-Codes and are not expanded
+ // - Table Prefices contain indexes to other codes
+ // - Table Suffices contain the raw codes to be output
+ while (OutCode >= FirstEntry)
+ {
+ if (OutIndex > 4096 || OutCode >= 4096)
+ return 0;
+ OutStack[OutIndex++] = Suffix[OutCode]; // Add suffix to Output Stack
+ OutCode = Prefix[OutCode]; // Loop with preffix
+ }
+
+ // NOW OutCode IS A RAW CODE, ADD IT TO OUTPUT STACK.
+ if (OutIndex > 4096)
+ return 0;
+ OutStack[OutIndex++] = (unsigned char) OutCode;
+
+ // ADD NEW ENTRY TO TABLE (PrevCode + OutCode)
+ // (EXCEPT IF PREVIOUS CODE WAS A CLEARCODE)
+ if (PrevCode != ClearCode)
+ {
+ Prefix[NextEntry] = PrevCode;
+ Suffix[NextEntry] = (unsigned char) OutCode;
+ NextEntry++;
+
+ // Prevent Translation table overflow:
+ if (NextEntry >= 4096)
+ return 0;
+
+ // INCREASE CodeSize IF NextEntry IS INVALID WITH CURRENT CodeSize
+ if (NextEntry >= (1 << CodeSize))
+ {
+ if (CodeSize < 12) CodeSize++;
+ else
+ {
+ ;
+ } // Do nothing. Maybe next is Clear Code.
+ }
+ }
+
+ PrevCode = Code;
+
+ // Avoid the possibility of overflow on 'bufOut'.
+ if (nPixels + OutIndex > maxPixels) OutIndex = maxPixels - nPixels;
+
+ // OUTPUT OutStack (LAST-IN FIRST-OUT ORDER)
+ for (n = OutIndex - 1; n >= 0; n--)
+ {
+ if (col == Width) // Check if new row.
+ {
+ if (Interlace)
+ {
+ // If interlaced::
+ if ((row&7) == 0) {row += 8; if (row >= Height) row = 4;}
+ else if ((row&3) == 0) {row += 8; if (row >= Height) row = 2;}
+ else if ((row&1) == 0) {row += 4; if (row >= Height) row = 1;}
+ else row += 2;
+ }
+ else // If not interlaced:
+ row++;
+
+ RowOffset = row * AlignedWidth; // Set new row offset
+ col = 0;
+ }
+ bufOut[RowOffset + col] = OutStack[n]; // Write output
+ col++; nPixels++; // Increase counters.
+ }
+
+ } // while (main decompressor loop)
+
+ return whichBit;
+}
+
+// Refer to WINIMAGE.TXT for copyright and patent notices on GIF and LZW.
+
+#pragma pack()
diff --git a/guilib/AnimatedGif.h b/guilib/AnimatedGif.h
new file mode 100644
index 0000000000..4cfc322b87
--- /dev/null
+++ b/guilib/AnimatedGif.h
@@ -0,0 +1,162 @@
+/*!
+\file AnimatedGif.h
+\brief
+*/
+
+
+// ****************************************************************************
+//
+// WINIMAGE.H : Generic classes for raster images (MSWindows specialization)
+//
+// Content: Class declarations of:
+// - class CAnimatedGif : Storage class for single images
+// - class CAnimatedGifSet : Storage class for sets of images
+// - class C_AnimationWindow : Window Class to display animations
+//
+// (Includes declarations of routines to Load and Save BMP files and to load
+// GIF files into these classes).
+//
+// --------------------------------------------------------------------------
+//
+// Copyright © 2000, Juan Soulie <jsoulie@cplusplus.com>
+//
+// Permission to use, copy, modify, distribute and sell this software or any
+// part thereof and/or its documentation for any purpose is granted without fee
+// provided that the above copyright notice and this permission notice appear
+// in all copies.
+//
+// This software is provided "as is" without express or implied warranty of
+// any kind. The author shall have no liability with respect to the
+// infringement of copyrights or patents that any modification to the content
+// of this file or this file itself may incur.
+//
+// ****************************************************************************
+
+
+#include "Texture.h" // for COLOR
+
+#pragma pack(1)
+
+#undef ALIGN
+#define ALIGN sizeof(int) ///< Windows GDI expects all int-aligned
+
+/*!
+ \ingroup textures
+ \brief
+ */
+typedef struct tagGUIRGBQUAD
+{
+ BYTE rgbBlue;
+ BYTE rgbGreen;
+ BYTE rgbRed;
+ BYTE rgbReserved;
+}
+GUIRGBQUAD;
+
+/*!
+ \ingroup textures
+ \brief
+ */
+typedef struct tagGUIBITMAPINFOHEADER
+{
+ DWORD biSize;
+ LONG biWidth;
+ LONG biHeight;
+ WORD biPlanes;
+ WORD biBitCount;
+ DWORD biCompression;
+ DWORD biSizeImage;
+ LONG biXPelsPerMeter;
+ LONG biYPelsPerMeter;
+ DWORD biClrUsed;
+ DWORD biClrImportant;
+}
+GUIBITMAPINFOHEADER;
+
+/*!
+ \ingroup textures
+ \brief
+ */
+typedef struct tagGUIBITMAPINFO
+{
+ GUIBITMAPINFOHEADER bmiHeader;
+ GUIRGBQUAD bmiColors[1];
+} GUIBITMAPINFO;
+
+#pragma pack()
+
+
+// ****************************************************************************
+// * CAnimatedGif *
+// * Storage class for single images *
+// ****************************************************************************
+/*!
+ \ingroup textures
+ \brief Storage class for single images
+ */
+class CAnimatedGif
+{
+public:
+ CAnimatedGif();
+ virtual ~CAnimatedGif();
+
+ // standard members:
+ int Width, Height; ///< Dimensions in pixels
+ int BPP; // Bits Per Pixel
+ char* Raster; ///< Bits of Raster Data (Byte Aligned)
+ COLOR* Palette; ///< Color Map
+ int BytesPerRow; ///< Width (in bytes) including alignment!
+ int Transparent; ///< Index of Transparent color (-1 for none)
+
+ // Extra members for animations:
+ int nLoops;
+ int xPos, yPos; ///< Relative Position
+ int Delay; ///< Delay after image in 1/1000 seconds.
+ int Transparency; ///< Animation Transparency.
+ // Windows GDI specific:
+ GUIBITMAPINFO* pbmi; ///< BITMAPINFO structure
+
+ // constructor and destructor:
+
+ // operator= (object copy)
+ CAnimatedGif& operator= (CAnimatedGif& rhs);
+
+ /// \brief Image initializer (allocates space for raster and palette):
+ void Init (int iWidth, int iHeight, int iBPP, int iLoops = 0);
+
+ inline char& Pixel (int x, int y) { return Raster[y*BytesPerRow + x];}
+
+};
+
+// ****************************************************************************
+// * CAnimatedGifSet *
+// * Storage class for sets of images *
+// ****************************************************************************
+/*!
+ \ingroup textures
+ \brief Storage class for sets of images
+ */
+class CAnimatedGifSet
+{
+public:
+
+ // constructor and destructor:
+ CAnimatedGifSet();
+ virtual ~CAnimatedGifSet();
+
+ int FrameWidth, FrameHeight; ///< Dimensions of ImageSet in pixels.
+ int nLoops; // Number of Loops (0 = infinite)
+
+ std::vector<CAnimatedGif*> m_vecimg; ///< Images' Vector.
+
+ void AddImage (CAnimatedGif*); ///< Append new image to vector (push_back)
+
+ int GetImageCount() const;
+ // File Formats:
+ int LoadGIF (const char* szFile);
+
+ void Release();
+protected:
+ unsigned char getbyte(FILE *fd);
+};
+
diff --git a/guilib/AudioContext.cpp b/guilib/AudioContext.cpp
new file mode 100644
index 0000000000..0c8e8dfe95
--- /dev/null
+++ b/guilib/AudioContext.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "AudioContext.h"
+#include "GUIAudioManager.h"
+#include "IAudioDeviceChangedCallback.h"
+#include "Settings.h"
+#include "GUISettings.h"
+#include "XBAudioConfig.h"
+#ifdef _WIN32PC
+#include "WINDirectSound.h"
+#endif
+extern HWND g_hWnd;
+
+
+CAudioContext g_audioContext;
+
+#ifdef _WIN32
+static GUID g_digitaldevice;
+BOOL CALLBACK DSEnumCallback(
+ LPGUID lpGuid,
+ LPCSTR lpcstrDescription,
+ LPCSTR lpcstrModule,
+ LPVOID lpContext
+)
+{
+ if(strstr(lpcstrDescription, "Digital Output") != NULL)
+ {
+ g_digitaldevice = *lpGuid;
+ return false;
+ }
+ return true;
+}
+#endif
+
+CAudioContext::CAudioContext()
+{
+ m_bAC3EncoderActive=false;
+ m_iDevice=DEFAULT_DEVICE;
+ m_strDevice.clear();
+#ifdef HAS_AUDIO
+#ifdef HAS_AUDIO_PASS_THROUGH
+ m_pAC97Device=NULL;
+#endif
+ m_pDirectSoundDevice=NULL;
+#endif
+}
+
+CAudioContext::~CAudioContext()
+{
+}
+
+// \brief Create a new device by type (DEFAULT_DEVICE, DIRECTSOUND_DEVICE, AC97_DEVICE)
+// Note: DEFAULT_DEVICE is created by the IAudioDeviceChangedCallback
+void CAudioContext::SetActiveDevice(int iDevice)
+{
+ /* if device is the same, no need to bother */
+#ifdef _WIN32PC
+ if(m_iDevice == iDevice && g_guiSettings.GetString("audiooutput.audiodevice").Equals(m_strDevice))
+ {
+ if (iDevice != NONE && m_pDirectSoundDevice)
+ {
+ DSCAPS devCaps = {0};
+ devCaps.dwSize = sizeof(devCaps);
+ if (SUCCEEDED(m_pDirectSoundDevice->GetCaps(&devCaps))) // Make sure the DirectSound interface is still valid.
+ return;
+ }
+ }
+
+#else
+ if(m_iDevice == iDevice)
+ return;
+#endif
+
+ if (iDevice==DEFAULT_DEVICE)
+ {
+ /* we just tell callbacks to init, it will setup audio */
+ g_audioManager.Initialize(iDevice);
+ return;
+ }
+
+ /* deinit current device */
+ RemoveActiveDevice();
+
+ m_iDevice=iDevice;
+ m_strDevice=g_guiSettings.GetString("audiooutput.audiodevice");
+
+#ifdef HAS_AUDIO
+ memset(&g_digitaldevice, 0, sizeof(GUID));
+ if (FAILED(DirectSoundEnumerate(DSEnumCallback, this)))
+ CLog::Log(LOGERROR, "%s - failed to enumerate output devices", __FUNCTION__);
+
+ if (iDevice==DIRECTSOUND_DEVICE
+ || iDevice==DIRECTSOUND_DEVICE_DIGITAL)
+ {
+ LPGUID guid = NULL;
+#ifdef _WIN32PC
+ CWDSound p_dsound;
+ std::vector<DSDeviceInfo > deviceList = p_dsound.GetSoundDevices();
+ std::vector<DSDeviceInfo >::const_iterator iter = deviceList.begin();
+ for (int i=0; iter != deviceList.end(); i++)
+ {
+ DSDeviceInfo dev = *iter;
+
+ if (g_guiSettings.GetString("audiooutput.audiodevice").Equals(dev.strDescription))
+ {
+ guid = dev.lpGuid;
+ CLog::Log(LOGDEBUG, "%s - selecting %s as output devices", __FUNCTION__, dev.strDescription.c_str());
+ break;
+ }
+
+ ++iter;
+ }
+#else
+ if(iDevice == DIRECTSOUND_DEVICE_DIGITAL
+ && ( g_digitaldevice.Data1 || g_digitaldevice.Data2
+ || g_digitaldevice.Data3 || g_digitaldevice.Data4 ))
+ guid = &g_digitaldevice;
+#endif
+
+ // Create DirectSound
+ if (FAILED(DirectSoundCreate( guid, &m_pDirectSoundDevice, NULL )))
+ {
+ CLog::Log(LOGERROR, "DirectSoundCreate() Failed");
+ return;
+ }
+ if (FAILED(m_pDirectSoundDevice->SetCooperativeLevel(g_hWnd, DSSCL_PRIORITY)))
+ {
+ CLog::Log(LOGERROR, "DirectSoundDevice::SetCooperativeLevel() Failed");
+ return;
+ }
+ }
+ else if (iDevice == DIRECTSOUND_DEVICE_DIGITAL)
+ {
+
+ }
+#ifdef HAS_AUDIO_PASS_THROUGH
+ else if (iDevice==AC97_DEVICE)
+ {
+ // Create AC97 Device
+ if (FAILED(Ac97CreateMediaObject(DSAC97_CHANNEL_DIGITAL, NULL, NULL, &m_pAC97Device)))
+ {
+ CLog::Log(LOGERROR, "Failed to create digital Ac97CreateMediaObject()");
+ return;
+ }
+ }
+#endif
+ // Don't log an error if the caller specifically asked for no device
+ // externalplayer does this to ensure all audio devices are closed
+ // during external playback
+ else if (iDevice != NONE)
+ {
+ CLog::Log(LOGERROR, "Failed to create audio device");
+ return;
+ }
+#endif
+ g_audioManager.Initialize(m_iDevice);
+}
+
+// \brief Return the active device type (NONE, DEFAULT_DEVICE, DIRECTSOUND_DEVICE, AC97_DEVICE)
+int CAudioContext::GetActiveDevice()
+{
+ return m_iDevice;
+}
+
+// \brief Remove the current sound device, eg. to setup new speaker config
+void CAudioContext::RemoveActiveDevice()
+{
+ g_audioManager.DeInitialize(m_iDevice);
+ m_iDevice=NONE;
+
+#ifdef HAS_AUDIO
+#ifdef HAS_AUDIO_PASS_THROUGH
+ SAFE_RELEASE(m_pAC97Device);
+#endif
+ SAFE_RELEASE(m_pDirectSoundDevice);
+#endif
+}
+
+// \brief set a new speaker config
+void CAudioContext::SetupSpeakerConfig(int iChannels, bool& bAudioOnAllSpeakers, bool bIsMusic)
+{
+ m_bAC3EncoderActive = false;
+ bAudioOnAllSpeakers = false;
+
+#ifdef HAS_AUDIO
+ DWORD spconfig = DSSPEAKER_USE_DEFAULT;
+ if (g_guiSettings.GetInt("audiooutput.mode") == AUDIO_DIGITAL)
+ {
+ if (((g_guiSettings.GetBool("musicplayer.outputtoallspeakers")) && (bIsMusic)) || (g_stSettings.m_currentVideoSettings.m_OutputToAllSpeakers && !bIsMusic))
+ {
+ if( g_audioConfig.GetAC3Enabled() )
+ {
+ bAudioOnAllSpeakers = true;
+ m_bAC3EncoderActive = true;
+ spconfig = DSSPEAKER_USE_DEFAULT; //Allows ac3 encoder should it be enabled
+ }
+ else
+ {
+ if (iChannels == 1)
+ spconfig = DSSPEAKER_MONO;
+ else
+ {
+ spconfig = DSSPEAKER_STEREO;
+ }
+ }
+ }
+ else
+ {
+ if (iChannels == 1)
+ spconfig = DSSPEAKER_MONO;
+ else if (iChannels == 2)
+ spconfig = DSSPEAKER_STEREO;
+ else
+ {
+ spconfig = DSSPEAKER_USE_DEFAULT; //Allows ac3 encoder should it be enabled
+ m_bAC3EncoderActive = g_audioConfig.GetAC3Enabled();
+ }
+ }
+ }
+ else // We don't want to use the Dolby Digital Encoder output. Downmix to surround instead.
+ {
+ if (iChannels == 1)
+ spconfig = DSSPEAKER_MONO;
+ else
+ {
+ // check if surround mode is allowed, if not then use normal stereo
+ // don't always set it to default as that enabled ac3 encoder if that is allowed in dash
+ // ruining quality
+ spconfig = DSSPEAKER_STEREO;
+ }
+ }
+
+ DWORD spconfig_old = DSSPEAKER_USE_DEFAULT;
+ if(m_pDirectSoundDevice)
+ {
+ m_pDirectSoundDevice->GetSpeakerConfig(&spconfig_old);
+ spconfig_old = DSSPEAKER_CONFIG(spconfig_old);
+ }
+
+ /* speaker config identical, no need to do anything */
+ if(spconfig == spconfig_old) return;
+#endif
+
+ /* speaker config has changed, caller need to recreate it */
+ RemoveActiveDevice();
+}
+
+bool CAudioContext::IsAC3EncoderActive() const
+{
+ return m_bAC3EncoderActive;
+}
+
+bool CAudioContext::IsPassthroughActive() const
+{
+ return (m_iDevice == DIRECTSOUND_DEVICE_DIGITAL);
+}
+
diff --git a/guilib/AudioContext.h b/guilib/AudioContext.h
new file mode 100644
index 0000000000..efa62f08da
--- /dev/null
+++ b/guilib/AudioContext.h
@@ -0,0 +1,79 @@
+/*!
+\file AudioContext.h
+\brief
+*/
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "StdString.h"
+
+// forward definitions
+class IAudioDeviceChangedCallback;
+
+#define DSMIXBINTYPE_STANDARD 1
+#define DSMIXBINTYPE_DMO 2
+#define DSMIXBINTYPE_AAC 3
+#define DSMIXBINTYPE_OGG 4
+#define DSMIXBINTYPE_CUSTOM 5
+#define DSMIXBINTYPE_STEREOALL 6
+#define DSMIXBINTYPE_STEREOLEFT 7
+#define DSMIXBINTYPE_STEREORIGHT 8
+
+class CAudioContext
+{
+public:
+ CAudioContext();
+ virtual ~CAudioContext();
+
+ void SetActiveDevice(int iDevice);
+ int GetActiveDevice();
+
+#ifdef HAS_AUDIO
+ LPDIRECTSOUND8 GetDirectSoundDevice() { return m_pDirectSoundDevice; }
+#ifdef HAS_AUDIO_PASS_THROUGH
+ LPAC97MEDIAOBJECT GetAc97Device() { return m_pAC97Device; }
+#endif
+#endif
+
+ void SetupSpeakerConfig(int iChannels, bool& bAudioOnAllSpeakers, bool bIsMusic=true);
+ bool IsAC3EncoderActive() const;
+ bool IsPassthroughActive() const;
+
+ enum AUDIO_DEVICE {NONE=0, DEFAULT_DEVICE, DIRECTSOUND_DEVICE, AC97_DEVICE, DIRECTSOUND_DEVICE_DIGITAL };
+protected:
+ void RemoveActiveDevice();
+
+#ifdef HAS_AUDIO
+#ifdef HAS_AUDIO_PASS_THROUGH
+ LPAC97MEDIAOBJECT m_pAC97Device;
+#endif
+ LPDIRECTSOUND8 m_pDirectSoundDevice;
+#endif
+
+ int m_iDevice;
+ CStdString m_strDevice;
+ bool m_bAC3EncoderActive;
+};
+
+extern CAudioContext g_audioContext;
diff --git a/guilib/DirectXGraphics.cpp b/guilib/DirectXGraphics.cpp
new file mode 100644
index 0000000000..5563b51304
--- /dev/null
+++ b/guilib/DirectXGraphics.cpp
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "DirectXGraphics.h"
+#include "Texture.h"
+#include "FileSystem/File.h"
+
+LPVOID XPhysicalAlloc(SIZE_T s, DWORD ulPhysicalAddress, DWORD ulAlignment, DWORD flProtect)
+{
+ return malloc(s);
+}
+
+void XPhysicalFree(LPVOID lpAddress)
+{
+ free(lpAddress);
+}
+
+D3DFORMAT GetD3DFormat(XB_D3DFORMAT format)
+{
+ switch (format)
+ {
+ case XB_D3DFMT_A8R8G8B8:
+ case XB_D3DFMT_LIN_A8R8G8B8:
+ return D3DFMT_LIN_A8R8G8B8;
+ case XB_D3DFMT_DXT1:
+ return D3DFMT_DXT1;
+ case XB_D3DFMT_DXT2:
+ return D3DFMT_DXT2;
+ case XB_D3DFMT_DXT4:
+ return D3DFMT_DXT4;
+ case XB_D3DFMT_P8:
+ return D3DFMT_LIN_A8R8G8B8;
+ default:
+ return D3DFMT_UNKNOWN;
+ }
+}
+
+DWORD BytesPerPixelFromFormat(XB_D3DFORMAT format)
+{
+ switch (format)
+ {
+ case XB_D3DFMT_A8R8G8B8:
+ case XB_D3DFMT_LIN_A8R8G8B8:
+ case XB_D3DFMT_DXT4:
+ return 4;
+ case XB_D3DFMT_P8:
+ case XB_D3DFMT_DXT1:
+ case XB_D3DFMT_DXT2:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+bool IsPalettedFormat(XB_D3DFORMAT format)
+{
+ if (format == XB_D3DFMT_P8)
+ return true;
+ return false;
+}
+
+void ParseTextureHeader(D3DTexture *tex, XB_D3DFORMAT &fmt, DWORD &width, DWORD &height, DWORD &pitch, DWORD &offset)
+{
+ fmt = (XB_D3DFORMAT)((tex->Format & 0xff00) >> 8);
+ offset = tex->Data;
+ if (tex->Size)
+ {
+ width = (tex->Size & 0x00000fff) + 1;
+ height = ((tex->Size & 0x00fff000) >> 12) + 1;
+ pitch = (((tex->Size & 0xff000000) >> 24) + 1) << 6;
+ }
+ else
+ {
+ width = 1 << ((tex->Format & 0x00f00000) >> 20);
+ height = 1 << ((tex->Format & 0x0f000000) >> 24);
+ pitch = width * BytesPerPixelFromFormat(fmt);
+ }
+}
+
+bool IsSwizzledFormat(XB_D3DFORMAT format)
+{
+ switch (format)
+ {
+ case XB_D3DFMT_A8R8G8B8:
+ case XB_D3DFMT_P8:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#ifdef HAS_DX
+HRESULT XGWriteSurfaceToFile(LPDIRECT3DSURFACE9 pSurface, const char *fileName)
+#else
+HRESULT XGWriteSurfaceToFile(void* pixels, int width, int height, const char *fileName)
+#endif
+{
+#ifdef HAS_DX
+ D3DLOCKED_RECT lr;
+ D3DSURFACE_DESC desc;
+ pSurface->GetDesc(&desc);
+ if (S_OK == pSurface->LockRect(&lr, NULL, 0))
+ {
+#endif
+ XFILE::CFile file;
+ if (file.OpenForWrite(fileName, true))
+ {
+ // create a 24bit BMP header
+ BMPHEAD bh;
+ memset((char *)&bh,0,sizeof(BMPHEAD));
+ memcpy(bh.id,"BM",2);
+ bh.headersize = 54L;
+ bh.infoSize = 0x28L;
+#ifdef HAS_DX
+ bh.width = desc.Width;
+ bh.height = desc.Height;
+#else
+ bh.width = width;
+ bh.height = height;
+#endif
+ bh.biPlanes = 1;
+ bh.bits = 24;
+ bh.biCompression = 0L;
+
+ //number of bytes per line in a BMP is divisible by 4
+ long bytesPerLine = bh.width * 3;
+ if (bytesPerLine & 0x0003)
+ {
+ bytesPerLine |= 0x0003;
+ ++bytesPerLine;
+ }
+ // filesize = headersize + bytesPerLine * number of lines
+ bh.filesize = bh.headersize + bytesPerLine * bh.height;
+
+ file.Write(&bh.id, sizeof(bh));
+
+ BYTE *lineBuf = new BYTE[bytesPerLine];
+ memset(lineBuf, 0, bytesPerLine);
+ // lines are stored in BMPs upside down
+#ifdef HAS_DX
+ for (UINT y = bh.height; y; --y)
+#else
+ for (UINT y = 1 ; y <= (UINT) bh.height ; ++y) //compensate for gl's inverted Y axis
+#endif
+ {
+#ifdef HAS_DX
+ BYTE *s = (BYTE *)lr.pBits + (y - 1) * lr.Pitch;
+ BYTE *d = lineBuf;
+#else
+ BYTE *s = (BYTE *)pixels + (y - 1) * 4 * width;
+ BYTE *d = lineBuf;
+#endif
+ for (UINT x = 0; x < (UINT) bh.width; x++)
+ {
+ *d++ = *(s + x * 4);
+ *d++ = *(s + x * 4 + 1);
+ *d++ = *(s + x * 4 + 2);
+ }
+ file.Write(lineBuf, bytesPerLine);
+ }
+ delete[] lineBuf;
+ file.Close();
+ }
+#ifdef HAS_DX
+ pSurface->UnlockRect();
+ }
+#endif
+ return S_OK;
+}
+
+// Unswizzle.
+// Format is:
+
+// 00 01 04 05
+// 02 03 06 07
+// 08 09 12 13
+// 10 11 14 15 ...
+
+// Currently only works for 32bit and 8bit textures, with power of 2 width and height
+void Unswizzle(const void *src, unsigned int depth, unsigned int width, unsigned int height, void *dest)
+{
+ for (UINT y = 0; y < height; y++)
+ {
+ UINT sy = 0;
+ if (y < width)
+ {
+ for (int bit = 0; bit < 16; bit++)
+ sy |= ((y >> bit) & 1) << (2*bit);
+ sy <<= 1; // y counts twice
+ }
+ else
+ {
+ UINT y_mask = y % width;
+ for (int bit = 0; bit < 16; bit++)
+ sy |= ((y_mask >> bit) & 1) << (2*bit);
+ sy <<= 1; // y counts twice
+ sy += (y / width) * width * width;
+ }
+ BYTE *d = (BYTE *)dest + y * width * depth;
+ for (UINT x = 0; x < width; x++)
+ {
+ UINT sx = 0;
+ if (x < height * 2)
+ {
+ for (int bit = 0; bit < 16; bit++)
+ sx |= ((x >> bit) & 1) << (2*bit);
+ }
+ else
+ {
+ int x_mask = x % (2*height);
+ for (int bit = 0; bit < 16; bit++)
+ sx |= ((x_mask >> bit) & 1) << (2*bit);
+ sx += (x / (2 * height)) * 2 * height * height;
+ }
+ BYTE *s = (BYTE *)src + (sx + sy)*depth;
+ for (unsigned int i = 0; i < depth; ++i)
+ *d++ = *s++;
+ }
+ }
+}
+
+void DXT1toARGB(const void *src, void *dest, unsigned int destWidth)
+{
+ const BYTE *b = (const BYTE *)src;
+ // colour is in R5G6B5 format, convert to R8G8B8
+ DWORD colour[4];
+ BYTE red[4];
+ BYTE green[4];
+ BYTE blue[4];
+ for (int i = 0; i < 2; i++)
+ {
+ red[i] = b[2*i+1] & 0xf8;
+ green[i] = ((b[2*i+1] & 0x7) << 5) | ((b[2*i] & 0xe0) >> 3);
+ blue[i] = (b[2*i] & 0x1f) << 3;
+ colour[i] = (red[i] << 16) | (green[i] << 8) | blue[i];
+ }
+ if (colour[0] > colour[1])
+ {
+ red[2] = (2 * red[0] + red[1] + 1) / 3;
+ green[2] = (2 * green[0] + green[1] + 1) / 3;
+ blue[2] = (2 * blue[0] + blue[1] + 1) / 3;
+ red[3] = (red[0] + 2 * red[1] + 1) / 3;
+ green[3] = (green[0] + 2 * green[1] + 1) / 3;
+ blue[3] = (blue[0] + 2 * blue[1] + 1) / 3;
+ for (int i = 0; i < 4; i++)
+ colour[i] = (red[i] << 16) | (green[i] << 8) | blue[i] | 0xFF000000;
+ }
+ else
+ {
+ red[2] = (red[0] + red[1]) / 2;
+ green[2] = (green[0] + green[1]) / 2;
+ blue[2] = (blue[0] + blue[1]) / 2;
+ for (int i = 0; i < 3; i++)
+ colour[i] = (red[i] << 16) | (green[i] << 8) | blue[i] | 0xFF000000;
+ colour[3] = 0; // transparent
+ }
+ // ok, now grab the bits
+ for (int y = 0; y < 4; y++)
+ {
+ DWORD *d = (DWORD *)dest + destWidth * y;
+ *d++ = colour[(b[4 + y] & 0x03)];
+ *d++ = colour[(b[4 + y] & 0x0c) >> 2];
+ *d++ = colour[(b[4 + y] & 0x30) >> 4];
+ *d++ = colour[(b[4 + y] & 0xc0) >> 6];
+ }
+}
+
+void DXT4toARGB(const void *src, void *dest, unsigned int destWidth)
+{
+ const BYTE *b = (const BYTE *)src;
+ BYTE alpha[8];
+ alpha[0] = b[0];
+ alpha[1] = b[1];
+ if (alpha[0] > alpha[1])
+ {
+ alpha[2] = (6 * alpha[0] + 1 * alpha[1]+ 3) / 7;
+ alpha[3] = (5 * alpha[0] + 2 * alpha[1] + 3) / 7; // bit code 011
+ alpha[4] = (4 * alpha[0] + 3 * alpha[1] + 3) / 7; // bit code 100
+ alpha[5] = (3 * alpha[0] + 4 * alpha[1] + 3) / 7; // bit code 101
+ alpha[6] = (2 * alpha[0] + 5 * alpha[1] + 3) / 7; // bit code 110
+ alpha[7] = (1 * alpha[0] + 6 * alpha[1] + 3) / 7; // bit code 111
+ }
+ else
+ {
+ alpha[2] = (4 * alpha[0] + 1 * alpha[1] + 2) / 5; // Bit code 010
+ alpha[3] = (3 * alpha[0] + 2 * alpha[1] + 2) / 5; // Bit code 011
+ alpha[4] = (2 * alpha[0] + 3 * alpha[1] + 2) / 5; // Bit code 100
+ alpha[5] = (1 * alpha[0] + 4 * alpha[1] + 2) / 5; // Bit code 101
+ alpha[6] = 0; // Bit code 110
+ alpha[7] = 255; // Bit code 111
+ }
+ // ok, now grab the bits
+ BYTE a[4][4];
+ a[0][0] = alpha[(b[2] & 0xe0) >> 5];
+ a[0][1] = alpha[(b[2] & 0x1c) >> 2];
+ a[0][2] = alpha[((b[2] & 0x03) << 1) | ((b[3] & 0x80) >> 7)];
+ a[0][3] = alpha[(b[3] & 0x70) >> 4];
+ a[1][0] = alpha[(b[3] & 0x0e) >> 1];
+ a[1][1] = alpha[((b[3] & 0x01) << 2) | ((b[4] & 0xc0) >> 6)];
+ a[1][2] = alpha[(b[4] & 0x38) >> 3];
+ a[1][3] = alpha[(b[4] & 0x07)];
+ a[2][0] = alpha[(b[5] & 0xe0) >> 5];
+ a[2][1] = alpha[(b[5] & 0x1c) >> 2];
+ a[2][2] = alpha[((b[5] & 0x03) << 1) | ((b[6] & 0x80) >> 7)];
+ a[2][3] = alpha[(b[6] & 0x70) >> 4];
+ a[3][0] = alpha[(b[6] & 0x0e) >> 1];
+ a[3][1] = alpha[((b[6] & 0x01) << 2) | ((b[7] & 0xc0) >> 6)];
+ a[3][2] = alpha[(b[7] & 0x38) >> 3];
+ a[3][3] = alpha[(b[7] & 0x07)];
+
+ b = (BYTE *)src + 8;
+ // colour is in R5G6B5 format, convert to R8G8B8
+ DWORD colour[4];
+ BYTE red[4];
+ BYTE green[4];
+ BYTE blue[4];
+ for (int i = 0; i < 2; i++)
+ {
+ red[i] = b[2*i+1] & 0xf8;
+ green[i] = ((b[2*i+1] & 0x7) << 5) | ((b[2*i] & 0xe0) >> 3);
+ blue[i] = (b[2*i] & 0x1f) << 3;
+ }
+ red[2] = (2 * red[0] + red[1] + 1) / 3;
+ green[2] = (2 * green[0] + green[1] + 1) / 3;
+ blue[2] = (2 * blue[0] + blue[1] + 1) / 3;
+ red[3] = (red[0] + 2 * red[1] + 1) / 3;
+ green[3] = (green[0] + 2 * green[1] + 1) / 3;
+ blue[3] = (blue[0] + 2 * blue[1] + 1) / 3;
+ for (int i = 0; i < 4; i++)
+ colour[i] = (red[i] << 16) | (green[i] << 8) | blue[i];
+ // and assign them to our texture
+ for (int y = 0; y < 4; y++)
+ {
+ DWORD *d = (DWORD *)dest + destWidth * y;
+ *d++ = colour[(b[4 + y] & 0x03)] | (a[y][0] << 24);
+ *d++ = colour[(b[4 + y] & 0x0e) >> 2] | (a[y][1] << 24);
+ *d++ = colour[(b[4 + y] & 0x30) >> 4] | (a[y][2] << 24);
+ *d++ = colour[(b[4 + y] & 0xe0) >> 6] | (a[y][3] << 24);
+ }
+
+}
+
+void ConvertDXT1(const void *src, unsigned int width, unsigned int height, void *dest)
+{
+ for (unsigned int y = 0; y < height; y += 4)
+ {
+ for (unsigned int x = 0; x < width; x += 4)
+ {
+ const BYTE *s = (const BYTE *)src + y * width / 2 + x * 2;
+ DWORD *d = (DWORD *)dest + y * width + x;
+ DXT1toARGB(s, d, width);
+ }
+ }
+}
+
+void ConvertDXT4(const void *src, unsigned int width, unsigned int height, void *dest)
+{
+ // [4 4 4 4][4 4 4 4]
+ //
+ //
+ //
+ for (unsigned int y = 0; y < height; y += 4)
+ {
+ for (unsigned int x = 0; x < width; x += 4)
+ {
+ const BYTE *s = (const BYTE *)src + y * width + x * 4;
+ DWORD *d = (DWORD *)dest + y * width + x;
+ DXT4toARGB(s, d, width);
+ }
+ }
+}
+
+void GetTextureFromData(D3DTexture *pTex, void *texData, CBaseTexture **ppTexture)
+{
+ XB_D3DFORMAT fmt;
+ DWORD width, height, pitch, offset;
+ ParseTextureHeader(pTex, fmt, width, height, pitch, offset);
+
+ *ppTexture = new CTexture(width, height, 32);
+
+ if (*ppTexture)
+ {
+ BYTE *texDataStart = (BYTE *)texData;
+ COLOR *color = (COLOR *)texData;
+ texDataStart += offset;
+/* DXMERGE - We should really support DXT1,DXT2 and DXT4 in both renderers
+ Perhaps we should extend CTexture::Update() to support a bunch of different texture types
+ Rather than assuming linear 32bits
+ We could just override, as at least then all the loading code from various texture formats
+ will be in one place
+
+ BYTE *dstPixels = (BYTE *)lr.pBits;
+ DWORD destPitch = lr.Pitch;
+ if (fmt == XB_D3DFMT_DXT1) // Not sure if these are 100% correct, but they seem to work :P
+ {
+ pitch /= 2;
+ destPitch /= 4;
+ }
+ else if (fmt == XB_D3DFMT_DXT2)
+ {
+ destPitch /= 4;
+ }
+ else if (fmt == XB_D3DFMT_DXT4)
+ {
+ pitch /= 4;
+ destPitch /= 4;
+ }
+*/
+ if (fmt == XB_D3DFMT_DXT1)
+ {
+ pitch = width * 4;
+ BYTE *decoded = new BYTE[pitch * height];
+ ConvertDXT1(texDataStart, width, height, decoded);
+ texDataStart = decoded;
+ }
+ else if (fmt == XB_D3DFMT_DXT2 || fmt == XB_D3DFMT_DXT4)
+ {
+ pitch = width * 4;
+ BYTE *decoded = new BYTE[pitch * height];
+ ConvertDXT4(texDataStart, width, height, decoded);
+ texDataStart = decoded;
+ }
+ if (IsSwizzledFormat(fmt))
+ { // first we unswizzle
+ BYTE *unswizzled = new BYTE[pitch * height];
+ Unswizzle(texDataStart, BytesPerPixelFromFormat(fmt), width, height, unswizzled);
+ texDataStart = unswizzled;
+ }
+
+ if (IsPalettedFormat(fmt))
+ (*ppTexture)->LoadPaletted(width, height, pitch, texDataStart, color);
+ else
+ (*ppTexture)->LoadFromMemory(width, height, pitch, 32, texDataStart);
+
+ if (IsSwizzledFormat(fmt) || fmt == XB_D3DFMT_DXT1 || fmt == XB_D3DFMT_DXT2 || fmt == XB_D3DFMT_DXT4)
+ {
+ delete[] texDataStart;
+ }
+ }
+}
diff --git a/guilib/DirectXGraphics.h b/guilib/DirectXGraphics.h
new file mode 100644
index 0000000000..45a58365bf
--- /dev/null
+++ b/guilib/DirectXGraphics.h
@@ -0,0 +1,176 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+class CBaseTexture;
+
+#include "gui3d.h"
+
+LPVOID XPhysicalAlloc(SIZE_T s, DWORD ulPhysicalAddress, DWORD ulAlignment, DWORD flProtect);
+void XPhysicalFree(LPVOID lpAddress);
+
+// XPR header
+struct XPR_HEADER
+{
+ DWORD dwMagic;
+ DWORD dwTotalSize;
+ DWORD dwHeaderSize;
+};
+#define XPR_MAGIC_VALUE (('0' << 24) | ('R' << 16) | ('P' << 8) | 'X')
+
+typedef enum _XB_D3DFORMAT
+{
+ XB_D3DFMT_UNKNOWN = 0xFFFFFFFF,
+
+ /* Swizzled formats */
+
+ XB_D3DFMT_A8R8G8B8 = 0x00000006,
+ XB_D3DFMT_X8R8G8B8 = 0x00000007,
+ XB_D3DFMT_R5G6B5 = 0x00000005,
+ XB_D3DFMT_R6G5B5 = 0x00000027,
+ XB_D3DFMT_X1R5G5B5 = 0x00000003,
+ XB_D3DFMT_A1R5G5B5 = 0x00000002,
+ XB_D3DFMT_A4R4G4B4 = 0x00000004,
+ XB_D3DFMT_A8 = 0x00000019,
+ XB_D3DFMT_A8B8G8R8 = 0x0000003A,
+ XB_D3DFMT_B8G8R8A8 = 0x0000003B,
+ XB_D3DFMT_R4G4B4A4 = 0x00000039,
+ XB_D3DFMT_R5G5B5A1 = 0x00000038,
+ XB_D3DFMT_R8G8B8A8 = 0x0000003C,
+ XB_D3DFMT_R8B8 = 0x00000029,
+ XB_D3DFMT_G8B8 = 0x00000028,
+
+ XB_D3DFMT_P8 = 0x0000000B,
+
+ XB_D3DFMT_L8 = 0x00000000,
+ XB_D3DFMT_A8L8 = 0x0000001A,
+ XB_D3DFMT_AL8 = 0x00000001,
+ XB_D3DFMT_L16 = 0x00000032,
+
+ XB_D3DFMT_V8U8 = 0x00000028,
+ XB_D3DFMT_L6V5U5 = 0x00000027,
+ XB_D3DFMT_X8L8V8U8 = 0x00000007,
+ XB_D3DFMT_Q8W8V8U8 = 0x0000003A,
+ XB_D3DFMT_V16U16 = 0x00000033,
+
+ XB_D3DFMT_D16_LOCKABLE = 0x0000002C,
+ XB_D3DFMT_D16 = 0x0000002C,
+ XB_D3DFMT_D24S8 = 0x0000002A,
+ XB_D3DFMT_F16 = 0x0000002D,
+ XB_D3DFMT_F24S8 = 0x0000002B,
+
+ /* YUV formats */
+
+ XB_D3DFMT_YUY2 = 0x00000024,
+ XB_D3DFMT_UYVY = 0x00000025,
+
+ /* Compressed formats */
+
+ XB_D3DFMT_DXT1 = 0x0000000C,
+ XB_D3DFMT_DXT2 = 0x0000000E,
+ XB_D3DFMT_DXT3 = 0x0000000E,
+ XB_D3DFMT_DXT4 = 0x0000000F,
+ XB_D3DFMT_DXT5 = 0x0000000F,
+
+ /* Linear formats */
+
+ XB_D3DFMT_LIN_A1R5G5B5 = 0x00000010,
+ XB_D3DFMT_LIN_A4R4G4B4 = 0x0000001D,
+ XB_D3DFMT_LIN_A8 = 0x0000001F,
+ XB_D3DFMT_LIN_A8B8G8R8 = 0x0000003F,
+ XB_D3DFMT_LIN_A8R8G8B8 = 0x00000012,
+ XB_D3DFMT_LIN_B8G8R8A8 = 0x00000040,
+ XB_D3DFMT_LIN_G8B8 = 0x00000017,
+ XB_D3DFMT_LIN_R4G4B4A4 = 0x0000003E,
+ XB_D3DFMT_LIN_R5G5B5A1 = 0x0000003D,
+ XB_D3DFMT_LIN_R5G6B5 = 0x00000011,
+ XB_D3DFMT_LIN_R6G5B5 = 0x00000037,
+ XB_D3DFMT_LIN_R8B8 = 0x00000016,
+ XB_D3DFMT_LIN_R8G8B8A8 = 0x00000041,
+ XB_D3DFMT_LIN_X1R5G5B5 = 0x0000001C,
+ XB_D3DFMT_LIN_X8R8G8B8 = 0x0000001E,
+
+ XB_D3DFMT_LIN_A8L8 = 0x00000020,
+ XB_D3DFMT_LIN_AL8 = 0x0000001B,
+ XB_D3DFMT_LIN_L16 = 0x00000035,
+ XB_D3DFMT_LIN_L8 = 0x00000013,
+
+ XB_D3DFMT_LIN_V16U16 = 0x00000036,
+ XB_D3DFMT_LIN_V8U8 = 0x00000017,
+ XB_D3DFMT_LIN_L6V5U5 = 0x00000037,
+ XB_D3DFMT_LIN_X8L8V8U8 = 0x0000001E,
+ XB_D3DFMT_LIN_Q8W8V8U8 = 0x00000012,
+
+ XB_D3DFMT_LIN_D24S8 = 0x0000002E,
+ XB_D3DFMT_LIN_F24S8 = 0x0000002F,
+ XB_D3DFMT_LIN_D16 = 0x00000030,
+ XB_D3DFMT_LIN_F16 = 0x00000031,
+
+ XB_D3DFMT_VERTEXDATA = 100,
+ XB_D3DFMT_INDEX16 = 101,
+
+ XB_D3DFMT_FORCE_DWORD =0x7fffffff
+} XB_D3DFORMAT;
+
+D3DFORMAT GetD3DFormat(XB_D3DFORMAT format);
+DWORD BytesPerPixelFromFormat(XB_D3DFORMAT format);
+bool IsPalettedFormat(XB_D3DFORMAT format);
+void ParseTextureHeader(D3DTexture *tex, XB_D3DFORMAT &fmt, DWORD &width, DWORD &height, DWORD &pitch, DWORD &offset);
+bool IsSwizzledFormat(XB_D3DFORMAT format);
+
+#ifndef _LINUX
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int8 uint8_t;
+typedef __int16 int16_t;
+#endif
+
+#pragma pack(push, 2)
+typedef struct {
+ uint8_t id[2]; // offset
+ uint32_t filesize; // 2
+ uint32_t reserved; // 6
+ uint32_t headersize; // 10
+ uint32_t infoSize; // 14
+ uint32_t width; // 18
+ uint32_t height; // 22
+ uint16_t biPlanes; // 26
+ uint16_t bits; // 28
+ uint32_t biCompression; // 30
+ uint32_t biSizeImage; // 34
+ uint32_t biXPelsPerMeter; // 38
+ uint32_t biYPelsPerMeter; // 42
+ uint32_t biClrUsed; // 46
+ uint32_t biClrImportant; // 50
+} BMPHEAD;
+#pragma pack(pop)
+
+#ifdef HAS_DX
+HRESULT XGWriteSurfaceToFile(LPDIRECT3DSURFACE9 pSurface, const char *fileName);
+#else
+HRESULT XGWriteSurfaceToFile(void* pixels, int width, int height, const char *fileName);
+#endif
+void Unswizzle(const void *src, unsigned int depth, unsigned int width, unsigned int height, void *dest);
+void DXT1toARGB(const void *src, void *dest, unsigned int destWidth);
+void DXT4toARGB(const void *src, void *dest, unsigned int destWidth);
+void ConvertDXT1(const void *src, unsigned int width, unsigned int height, void *dest);
+void ConvertDXT4(const void *src, unsigned int width, unsigned int height, void *dest);
+void GetTextureFromData(D3DTexture *pTex, void *texData, CBaseTexture** ppTexture);
diff --git a/guilib/FrameBufferObject.cpp b/guilib/FrameBufferObject.cpp
new file mode 100644
index 0000000000..fb9530c8da
--- /dev/null
+++ b/guilib/FrameBufferObject.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+
+#ifdef HAS_GL
+#include "../xbmc/Settings.h"
+#include "WindowingFactory.h"
+#include "FrameBufferObject.h"
+#include "utils/log.h"
+
+//////////////////////////////////////////////////////////////////////
+// CFrameBufferObject
+//////////////////////////////////////////////////////////////////////
+
+CFrameBufferObject::CFrameBufferObject()
+{
+ m_fbo = 0;
+ m_valid = false;
+ m_supported = false;
+ m_bound = false;
+ m_texid = 0;
+}
+
+bool CFrameBufferObject::IsSupported()
+{
+ if(g_Windowing.IsExtSupported("GL_EXT_framebuffer_object"))
+ m_supported = true;
+ else
+ m_supported = false;
+ return m_supported;
+}
+
+bool CFrameBufferObject::Initialize()
+{
+ if (!IsSupported())
+ return false;
+
+ Cleanup();
+
+ glGenFramebuffersEXT(1, &m_fbo);
+ VerifyGLState();
+
+ if (!m_fbo)
+ return false;
+
+ m_valid = true;
+ return true;
+}
+
+void CFrameBufferObject::Cleanup()
+{
+ if (!IsValid())
+ return;
+
+ if (m_fbo)
+ glDeleteFramebuffersEXT(1, &m_fbo);
+
+ if (m_texid)
+ glDeleteTextures(1, &m_texid);
+
+ m_texid = 0;
+ m_fbo = 0;
+ m_valid = false;
+ m_bound = false;
+}
+
+bool CFrameBufferObject::CreateAndBindToTexture(GLenum target, int width, int height, GLenum format,
+ GLenum filter, GLenum clampmode)
+{
+ if (!IsValid())
+ return false;
+
+ if (m_texid)
+ glDeleteTextures(1, &m_texid);
+
+ glGenTextures(1, &m_texid);
+ glBindTexture(target, m_texid);
+ glTexImage2D(target, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL);
+ glTexParameteri(target, GL_TEXTURE_WRAP_S, clampmode);
+ glTexParameteri(target, GL_TEXTURE_WRAP_T, clampmode);
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
+ VerifyGLState();
+ return BindToTexture(target, m_texid);
+}
+
+void CFrameBufferObject::SetFiltering(GLenum target, GLenum mode)
+{
+ glBindTexture(target, m_texid);
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mode);
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, mode);
+}
+
+bool CFrameBufferObject::BindToTexture(GLenum target, GLuint texid)
+{
+ if (!IsValid())
+ return false;
+
+ m_bound = false;
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ glBindTexture(target, texid);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, target, texid, 0);
+ VerifyGLState();
+ GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+ {
+ VerifyGLState();
+ return false;
+ }
+ m_bound = true;
+ return true;
+}
+
+#endif
diff --git a/guilib/FrameBufferObject.h b/guilib/FrameBufferObject.h
new file mode 100644
index 0000000000..cc3d679daf
--- /dev/null
+++ b/guilib/FrameBufferObject.h
@@ -0,0 +1,111 @@
+#ifndef __FRAMEBUFFEROBJECT_H__
+#define __FRAMEBUFFEROBJECT_H__
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+
+#ifdef HAS_GL
+
+//
+// CFrameBufferObject
+// A class that abstracts FBOs to facilitate Render To Texture
+//
+// Requires OpenGL 1.5+ or the GL_EXT_framebuffer_object extension.
+//
+// Usage:
+//
+// CFrameBufferObject *fbo = new CFrameBufferObject();
+// fbo->Initialize();
+// fbo->CreateAndBindToTexture(GL_TEXTURE_2D, 256, 256, GL_RGBA);
+// OR fbo->BindToTexture(GL_TEXTURE_2D, <existing texture ID>);
+// fbo->BeginRender();
+// <normal GL rendering calls>
+// fbo->EndRender();
+// bind and use texture anywhere
+// glBindTexture(GL_TEXTURE_2D, fbo->Texture());
+//
+
+
+class CFrameBufferObject
+{
+public:
+ // Constructor
+ CFrameBufferObject();
+
+ // returns true if FBO support is detected
+ bool IsSupported();
+
+ // returns true if FBO has been initialized
+ bool IsValid() { return m_valid; }
+
+ // returns true if FBO has a texture bound to it
+ bool IsBound() { return m_bound; }
+
+ // initialize the FBO
+ bool Initialize();
+
+ // Cleanup
+ void Cleanup();
+
+ // Bind to an exiting texture
+ bool BindToTexture(GLenum target, GLuint texid);
+
+ // Set texture filtering
+ void SetFiltering(GLenum target, GLenum mode);
+
+ // Create a new texture and bind to it
+ bool CreateAndBindToTexture(GLenum target, int width, int height, GLenum format,
+ GLenum filter=GL_LINEAR, GLenum clamp=GL_CLAMP_TO_EDGE);
+
+ // Return the internally created texture ID
+ GLuint Texture() { return m_texid; }
+
+ // Begin rendering to FBO
+ bool BeginRender()
+ {
+ if (IsValid() && IsBound())
+ {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ return true;
+ }
+ return false;
+ }
+
+ // Finish rendering to FBO
+ void EndRender()
+ {
+ if (IsValid())
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ }
+
+private:
+ GLuint m_fbo;
+ bool m_valid;
+ bool m_bound;
+ bool m_supported;
+ GLuint m_texid;
+};
+
+#endif
+
+#endif
diff --git a/guilib/GUIActionDescriptor.h b/guilib/GUIActionDescriptor.h
new file mode 100644
index 0000000000..6bd0ec1966
--- /dev/null
+++ b/guilib/GUIActionDescriptor.h
@@ -0,0 +1,36 @@
+#ifndef GUI_ACTION_DESCRIPTOR
+#define GUI_ACTION_DESCRIPTOR
+
+#include "StdString.h"
+#include "system.h"
+
+class CGUIActionDescriptor
+{
+public:
+ typedef enum { LANG_XBMC = 0, LANG_PYTHON = 1 /*, LANG_JAVASCRIPT = 2 */ } ActionLang;
+
+ CGUIActionDescriptor()
+ {
+ m_lang = LANG_XBMC;
+ m_action = "";
+ m_sourceWindowId = -1;
+ }
+
+ CGUIActionDescriptor(CStdString& action)
+ {
+ m_lang = LANG_XBMC;
+ m_action = action;
+ }
+
+ CGUIActionDescriptor(ActionLang lang, CStdString& action)
+ {
+ m_lang = lang;
+ m_action = action;
+ }
+
+ CStdString m_action;
+ ActionLang m_lang;
+ DWORD m_sourceWindowId; // the id of the window that was a source of an action
+};
+
+#endif
diff --git a/guilib/GUIAudioManager.cpp b/guilib/GUIAudioManager.cpp
new file mode 100644
index 0000000000..8b7dfee7cc
--- /dev/null
+++ b/guilib/GUIAudioManager.cpp
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "GUIAudioManager.h"
+#include "Key.h"
+#include "AudioContext.h"
+#include "GUISound.h"
+#include "GUISettings.h"
+#include "ButtonTranslator.h"
+#include "utils/SingleLock.h"
+#include "../xbmc/Util.h"
+#include "../xbmc/FileSystem/Directory.h"
+#include "tinyXML/tinyxml.h"
+#ifdef HAS_SDL_AUDIO
+#include <SDL/SDL_mixer.h>
+#endif
+
+using namespace std;
+using namespace DIRECTORY;
+
+CGUIAudioManager g_audioManager;
+
+CGUIAudioManager::CGUIAudioManager()
+{
+ m_bInitialized = false;
+ m_actionSound=NULL;
+ m_bEnabled=true;
+}
+
+CGUIAudioManager::~CGUIAudioManager()
+{
+
+}
+
+void CGUIAudioManager::Initialize(int iDevice)
+{
+ if (m_bInitialized || !m_bEnabled)
+ return;
+
+ if (g_guiSettings.GetString("lookandfeel.soundskin")=="OFF")
+ return;
+
+ if (iDevice==CAudioContext::DEFAULT_DEVICE)
+ {
+ CSingleLock lock(m_cs);
+ CLog::Log(LOGDEBUG, "CGUIAudioManager::Initialize");
+#ifdef _WIN32
+ bool bAudioOnAllSpeakers=false;
+ g_audioContext.SetupSpeakerConfig(2, bAudioOnAllSpeakers);
+ g_audioContext.SetActiveDevice(CAudioContext::DIRECTSOUND_DEVICE);
+ m_bInitialized = true;
+#elif defined(HAS_SDL_AUDIO)
+ Mix_CloseAudio();
+ if (Mix_OpenAudio(44100, AUDIO_S16, 2, 4096))
+ CLog::Log(LOGERROR, "Unable to open audio mixer");
+ m_bInitialized = true;
+#endif
+ }
+}
+
+void CGUIAudioManager::DeInitialize(int iDevice)
+{
+ if (!(iDevice == CAudioContext::DIRECTSOUND_DEVICE || iDevice == CAudioContext::DEFAULT_DEVICE)) return;
+
+ if (!m_bInitialized)
+ return;
+
+ CSingleLock lock(m_cs);
+ CLog::Log(LOGDEBUG, "CGUIAudioManager::DeInitialize");
+
+ if (m_actionSound) // Wait for finish when an action sound is playing
+ while(m_actionSound->IsPlaying()) {}
+
+ Stop();
+#ifdef HAS_SDL_AUDIO
+ Mix_CloseAudio();
+#endif
+ m_bInitialized = false;
+
+}
+void CGUIAudioManager::Stop()
+{
+ CSingleLock lock(m_cs);
+ if (m_actionSound)
+ {
+ delete m_actionSound;
+ m_actionSound=NULL;
+ }
+
+ for (windowSoundsMap::iterator it=m_windowSounds.begin();it!=m_windowSounds.end();it++)
+ {
+ CGUISound* sound=it->second;
+ if (sound->IsPlaying())
+ sound->Stop();
+
+ delete sound;
+ }
+ m_windowSounds.clear();
+
+ for (pythonSoundsMap::iterator it1=m_pythonSounds.begin();it1!=m_pythonSounds.end();it1++)
+ {
+ CGUISound* sound=it1->second;
+ if (sound->IsPlaying())
+ sound->Stop();
+
+ delete sound;
+ }
+ m_pythonSounds.clear();
+}
+
+// \brief Clear any unused audio buffers
+void CGUIAudioManager::FreeUnused()
+{
+ CSingleLock lock(m_cs);
+
+ // Free the sound from the last action
+ if (m_actionSound && !m_actionSound->IsPlaying())
+ {
+ delete m_actionSound;
+ m_actionSound=NULL;
+ }
+
+ // Free sounds from windows
+ windowSoundsMap::iterator it=m_windowSounds.begin();
+ while (it!=m_windowSounds.end())
+ {
+ CGUISound* sound=it->second;
+ if (!sound->IsPlaying())
+ {
+ delete sound;
+ m_windowSounds.erase(it++);
+ }
+ else ++it;
+ }
+
+ // Free sounds from python
+ pythonSoundsMap::iterator it1=m_pythonSounds.begin();
+ while (it1!=m_pythonSounds.end())
+ {
+ CGUISound* sound=it1->second;
+ if (!sound->IsPlaying())
+ {
+ delete sound;
+ m_pythonSounds.erase(it1++);
+ }
+ else ++it1;
+ }
+}
+
+// \brief Play a sound associated with a CAction
+void CGUIAudioManager::PlayActionSound(const CAction& action)
+{
+ // it's not possible to play gui sounds when passthrough is active
+ if (!m_bInitialized || !m_bEnabled || g_audioContext.IsPassthroughActive())
+ return;
+
+ CSingleLock lock(m_cs);
+
+ actionSoundMap::iterator it=m_actionSoundMap.find(action.id);
+ if (it==m_actionSoundMap.end())
+ return;
+
+ if (m_actionSound)
+ {
+ delete m_actionSound;
+ m_actionSound=NULL;
+ }
+
+ m_actionSound=new CGUISound();
+ if (!m_actionSound->Load(CUtil::AddFileToFolder(m_strMediaDir, it->second)))
+ {
+ delete m_actionSound;
+ m_actionSound=NULL;
+ return;
+ }
+
+ m_actionSound->Play();
+}
+
+// \brief Play a sound associated with a window and its event
+// Events: SOUND_INIT, SOUND_DEINIT
+void CGUIAudioManager::PlayWindowSound(int id, WINDOW_SOUND event)
+{
+ // it's not possible to play gui sounds when passthrough is active
+ if (!m_bInitialized || !m_bEnabled || g_audioContext.IsPassthroughActive())
+ return;
+
+ CSingleLock lock(m_cs);
+
+ windowSoundMap::iterator it=m_windowSoundMap.find(id);
+ if (it==m_windowSoundMap.end())
+ return;
+
+ CWindowSounds sounds=it->second;
+ CStdString strFile;
+ switch (event)
+ {
+ case SOUND_INIT:
+ strFile=sounds.strInitFile;
+ break;
+ case SOUND_DEINIT:
+ strFile=sounds.strDeInitFile;
+ break;
+ }
+
+ if (strFile.IsEmpty())
+ return;
+
+ // One sound buffer for each window
+ windowSoundsMap::iterator itsb=m_windowSounds.find(id);
+ if (itsb!=m_windowSounds.end())
+ {
+ CGUISound* sound=itsb->second;
+ if (sound->IsPlaying())
+ sound->Stop();
+ delete sound;
+ m_windowSounds.erase(itsb++);
+ }
+
+ CGUISound* sound=new CGUISound();
+ if (!sound->Load(CUtil::AddFileToFolder(m_strMediaDir, strFile)))
+ {
+ delete sound;
+ return;
+ }
+
+ m_windowSounds.insert(pair<int, CGUISound*>(id, sound));
+ sound->Play();
+}
+
+// \brief Play a sound given by filename
+void CGUIAudioManager::PlayPythonSound(const CStdString& strFileName)
+{
+ // it's not possible to play gui sounds when passthrough is active
+ if (!m_bInitialized || !m_bEnabled || g_audioContext.IsPassthroughActive())
+ return;
+
+ CSingleLock lock(m_cs);
+
+ // If we already loaded the sound, just play it
+ pythonSoundsMap::iterator itsb=m_pythonSounds.find(strFileName);
+ if (itsb!=m_pythonSounds.end())
+ {
+ CGUISound* sound=itsb->second;
+ if (sound->IsPlaying())
+ sound->Stop();
+
+ sound->Play();
+
+ return;
+ }
+
+ CGUISound* sound=new CGUISound();
+ if (!sound->Load(strFileName))
+ {
+ delete sound;
+ return;
+ }
+
+ m_pythonSounds.insert(pair<CStdString, CGUISound*>(strFileName, sound));
+ sound->Play();
+}
+
+// \brief Load the config file (sounds.xml) for nav sounds
+// Can be located in a folder "sounds" in the skin or from a
+// subfolder of the folder "sounds" in the root directory of
+// xbmc
+bool CGUIAudioManager::Load()
+{
+ m_actionSoundMap.clear();
+ m_windowSoundMap.clear();
+
+ Enable(m_bEnabled); // make sure we initialize or deinitialize
+
+ if (g_guiSettings.GetString("lookandfeel.soundskin")=="OFF")
+ return true;
+
+ if (g_guiSettings.GetString("lookandfeel.soundskin")=="SKINDEFAULT")
+ {
+ m_strMediaDir="special://home/skin/" + g_guiSettings.GetString("lookandfeel.skin") + "/sounds";
+ if ( ! CDirectory::Exists( m_strMediaDir ) )
+ {
+ m_strMediaDir = CUtil::AddFileToFolder("special://xbmc/skin", g_guiSettings.GetString("lookandfeel.skin"));
+ m_strMediaDir = CUtil::AddFileToFolder(m_strMediaDir, "sounds");
+ }
+ }
+ else
+ m_strMediaDir = CUtil::AddFileToFolder("special://xbmc/sounds", g_guiSettings.GetString("lookandfeel.soundskin"));
+
+ CStdString strSoundsXml = CUtil::AddFileToFolder(m_strMediaDir, "sounds.xml");
+
+ // Load our xml file
+ TiXmlDocument xmlDoc;
+
+ CLog::Log(LOGINFO, "Loading %s", strSoundsXml.c_str());
+
+ // Load the config file
+ if (!xmlDoc.LoadFile(strSoundsXml))
+ {
+ CLog::Log(LOGNOTICE, "%s, Line %d\n%s", strSoundsXml.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
+ return false;
+ }
+
+ TiXmlElement* pRoot = xmlDoc.RootElement();
+ CStdString strValue = pRoot->Value();
+ if ( strValue != "sounds")
+ {
+ CLog::Log(LOGNOTICE, "%s Doesn't contain <sounds>", strSoundsXml.c_str());
+ return false;
+ }
+
+ // Load sounds for actions
+ TiXmlElement* pActions = pRoot->FirstChildElement("actions");
+ if (pActions)
+ {
+ TiXmlNode* pAction = pActions->FirstChild("action");
+
+ while (pAction)
+ {
+ TiXmlNode* pIdNode = pAction->FirstChild("name");
+ int id = 0; // action identity
+ if (pIdNode && pIdNode->FirstChild())
+ {
+ CButtonTranslator::TranslateActionString(pIdNode->FirstChild()->Value(), id);
+ }
+
+ TiXmlNode* pFileNode = pAction->FirstChild("file");
+ CStdString strFile;
+ if (pFileNode && pFileNode->FirstChild())
+ strFile+=pFileNode->FirstChild()->Value();
+
+ if (id > 0 && !strFile.IsEmpty())
+ m_actionSoundMap.insert(pair<int, CStdString>(id, strFile));
+
+ pAction = pAction->NextSibling();
+ }
+ }
+
+ // Load window specific sounds
+ TiXmlElement* pWindows = pRoot->FirstChildElement("windows");
+ if (pWindows)
+ {
+ TiXmlNode* pWindow = pWindows->FirstChild("window");
+
+ while (pWindow)
+ {
+ int id = 0;
+
+ TiXmlNode* pIdNode = pWindow->FirstChild("name");
+ if (pIdNode)
+ {
+ if (pIdNode->FirstChild())
+ id = CButtonTranslator::TranslateWindowString(pIdNode->FirstChild()->Value());
+ }
+
+ CWindowSounds sounds;
+ LoadWindowSound(pWindow, "activate", sounds.strInitFile);
+ LoadWindowSound(pWindow, "deactivate", sounds.strDeInitFile);
+
+ if (id > 0)
+ m_windowSoundMap.insert(pair<int, CWindowSounds>(id, sounds));
+
+ pWindow = pWindow->NextSibling();
+ }
+ }
+
+ return true;
+}
+
+// \brief Load a window node of the config file (sounds.xml)
+bool CGUIAudioManager::LoadWindowSound(TiXmlNode* pWindowNode, const CStdString& strIdentifier, CStdString& strFile)
+{
+ if (!pWindowNode)
+ return false;
+
+ TiXmlNode* pFileNode = pWindowNode->FirstChild(strIdentifier);
+ if (pFileNode && pFileNode->FirstChild())
+ {
+ strFile = pFileNode->FirstChild()->Value();
+ return true;
+ }
+
+ return false;
+}
+
+// \brief Enable/Disable nav sounds
+void CGUIAudioManager::Enable(bool bEnable)
+{
+ m_bEnabled=bEnable;
+
+ // always deinit audio when we don't want gui sounds
+ if (g_guiSettings.GetString("lookandfeel.soundskin")=="OFF")
+ bEnable = false;
+
+ if (bEnable)
+ Initialize(CAudioContext::DEFAULT_DEVICE);
+ else if (!bEnable)
+ DeInitialize(CAudioContext::DEFAULT_DEVICE);
+}
+
+// \brief Sets the volume of all playing sounds
+void CGUIAudioManager::SetVolume(int iLevel)
+{
+ CSingleLock lock(m_cs);
+
+ if (m_actionSound)
+ m_actionSound->SetVolume(iLevel);
+
+ windowSoundsMap::iterator it=m_windowSounds.begin();
+ while (it!=m_windowSounds.end())
+ {
+ if (it->second)
+ it->second->SetVolume(iLevel);
+
+ ++it;
+ }
+
+ pythonSoundsMap::iterator it1=m_pythonSounds.begin();
+ while (it1!=m_pythonSounds.end())
+ {
+ if (it1->second)
+ it1->second->SetVolume(iLevel);
+
+ ++it1;
+ }
+}
diff --git a/guilib/GUIAudioManager.h b/guilib/GUIAudioManager.h
new file mode 100644
index 0000000000..a31573c913
--- /dev/null
+++ b/guilib/GUIAudioManager.h
@@ -0,0 +1,88 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "IAudioDeviceChangedCallback.h"
+#include "utils/CriticalSection.h"
+#include "utils/log.h"
+#include "StdString.h"
+
+#include <map>
+
+// forward definitions
+class CAction;
+class CGUISound;
+class TiXmlNode;
+
+enum WINDOW_SOUND { SOUND_INIT = 0, SOUND_DEINIT };
+
+class CGUIAudioManager : public IAudioDeviceChangedCallback
+{
+ class CWindowSounds
+ {
+ public:
+ CStdString strInitFile;
+ CStdString strDeInitFile;
+ };
+
+public:
+ CGUIAudioManager();
+ virtual ~CGUIAudioManager();
+
+ virtual void Initialize(int iDevice);
+ virtual void DeInitialize(int iDevice);
+
+ bool Load();
+
+ void PlayActionSound(const CAction& action);
+ void PlayWindowSound(int id, WINDOW_SOUND event);
+ void PlayPythonSound(const CStdString& strFileName);
+
+ void FreeUnused();
+
+ void Enable(bool bEnable);
+ void SetVolume(int iLevel);
+ void Stop();
+private:
+ bool LoadWindowSound(TiXmlNode* pWindowNode, const CStdString& strIdentifier, CStdString& strFile);
+
+ typedef std::map<int, CStdString> actionSoundMap;
+ typedef std::map<int, CWindowSounds> windowSoundMap;
+
+ typedef std::map<CStdString, CGUISound*> pythonSoundsMap;
+ typedef std::map<int, CGUISound*> windowSoundsMap;
+
+ actionSoundMap m_actionSoundMap;
+ windowSoundMap m_windowSoundMap;
+
+ CGUISound* m_actionSound;
+ windowSoundsMap m_windowSounds;
+ pythonSoundsMap m_pythonSounds;
+
+ CStdString m_strMediaDir;
+ bool m_bEnabled;
+ bool m_bInitialized;
+
+ CCriticalSection m_cs;
+};
+
+extern CGUIAudioManager g_audioManager;
diff --git a/guilib/GUIBaseContainer.cpp b/guilib/GUIBaseContainer.cpp
new file mode 100644
index 0000000000..332c6dce34
--- /dev/null
+++ b/guilib/GUIBaseContainer.cpp
@@ -0,0 +1,1183 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIBaseContainer.h"
+#include "GUIControlFactory.h"
+#include "utils/CharsetConverter.h"
+#include "utils/GUIInfoManager.h"
+#include "utils/log.h"
+#include "GUILabelControl.h"
+#include "XMLUtils.h"
+#include "SkinInfo.h"
+#include "StringUtils.h"
+#include "FileItem.h"
+#include "Key.h"
+
+using namespace std;
+
+#define HOLD_TIME_START 1000
+#define HOLD_TIME_END 4000
+
+CGUIBaseContainer::CGUIBaseContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, int scrollTime, int preloadItems)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+{
+ m_cursor = 0;
+ m_offset = 0;
+ m_scrollOffset = 0;
+ m_scrollSpeed = 0;
+ m_scrollLastTime = 0;
+ m_scrollTime = scrollTime ? scrollTime : 1;
+ m_lastHoldTime = 0;
+ m_itemsPerPage = 10;
+ m_pageControl = 0;
+ m_renderTime = 0;
+ m_orientation = orientation;
+ m_analogScrollCount = 0;
+ m_lastItem = NULL;
+ m_staticContent = false;
+ m_staticUpdateTime = 0;
+ m_wasReset = false;
+ m_layout = NULL;
+ m_focusedLayout = NULL;
+ m_cacheItems = preloadItems;
+}
+
+CGUIBaseContainer::~CGUIBaseContainer(void)
+{
+}
+
+void CGUIBaseContainer::Render()
+{
+ ValidateOffset();
+
+ if (m_bInvalidated)
+ UpdateLayout();
+
+ if (!m_layout || !m_focusedLayout) return;
+
+ UpdateScrollOffset();
+
+ int offset = (int)floorf(m_scrollOffset / m_layout->Size(m_orientation));
+
+ int cacheBefore, cacheAfter;
+ GetCacheOffsets(cacheBefore, cacheAfter);
+
+ // Free memory not used on screen
+ if ((int)m_items.size() > m_itemsPerPage + cacheBefore + cacheAfter)
+ FreeMemory(CorrectOffset(offset - cacheBefore, 0), CorrectOffset(offset + m_itemsPerPage + 1 + cacheAfter, 0));
+
+ g_graphicsContext.SetClipRegion(m_posX, m_posY, m_width, m_height);
+ float pos = (m_orientation == VERTICAL) ? m_posY : m_posX;
+ float end = (m_orientation == VERTICAL) ? m_posY + m_height : m_posX + m_width;
+
+ // we offset our draw position to take into account scrolling and whether or not our focused
+ // item is offscreen "above" the list.
+ float drawOffset = (offset - cacheBefore) * m_layout->Size(m_orientation) - m_scrollOffset;
+ if (m_offset + m_cursor < offset)
+ drawOffset += m_focusedLayout->Size(m_orientation) - m_layout->Size(m_orientation);
+ pos += drawOffset;
+ end += cacheAfter * m_layout->Size(m_orientation);
+
+ float focusedPos = 0;
+ CGUIListItemPtr focusedItem;
+ int current = offset - cacheBefore;
+ while (pos < end && m_items.size())
+ {
+ int itemNo = CorrectOffset(current, 0);
+ if (itemNo >= (int)m_items.size())
+ break;
+ bool focused = (current == m_offset + m_cursor);
+ if (itemNo >= 0)
+ {
+ CGUIListItemPtr item = m_items[itemNo];
+ // render our item
+ if (focused)
+ {
+ focusedPos = pos;
+ focusedItem = item;
+ }
+ else
+ {
+ if (m_orientation == VERTICAL)
+ RenderItem(m_posX, pos, item.get(), false);
+ else
+ RenderItem(pos, m_posY, item.get(), false);
+ }
+ }
+ // increment our position
+ pos += focused ? m_focusedLayout->Size(m_orientation) : m_layout->Size(m_orientation);
+ current++;
+ }
+ // render focused item last so it can overlap other items
+ if (focusedItem)
+ {
+ if (m_orientation == VERTICAL)
+ RenderItem(m_posX, focusedPos, focusedItem.get(), true);
+ else
+ RenderItem(focusedPos, m_posY, focusedItem.get(), true);
+ }
+
+ g_graphicsContext.RestoreClipRegion();
+
+ UpdatePageControl(offset);
+
+ CGUIControl::Render();
+}
+
+
+void CGUIBaseContainer::RenderItem(float posX, float posY, CGUIListItem *item, bool focused)
+{
+ if (!m_focusedLayout || !m_layout) return;
+
+ // set the origin
+ g_graphicsContext.SetOrigin(posX, posY);
+
+ if (m_bInvalidated)
+ item->SetInvalid();
+ if (focused)
+ {
+ if (!item->GetFocusedLayout())
+ {
+ CGUIListItemLayout *layout = new CGUIListItemLayout(*m_focusedLayout);
+ item->SetFocusedLayout(layout);
+ }
+ if (item->GetFocusedLayout())
+ {
+ if (item != m_lastItem || !HasFocus())
+ {
+ item->GetFocusedLayout()->SetFocusedItem(0);
+ }
+ if (item != m_lastItem && HasFocus())
+ {
+ item->GetFocusedLayout()->ResetAnimation(ANIM_TYPE_UNFOCUS);
+ unsigned int subItem = 1;
+ if (m_lastItem && m_lastItem->GetFocusedLayout())
+ subItem = m_lastItem->GetFocusedLayout()->GetFocusedItem();
+ item->GetFocusedLayout()->SetFocusedItem(subItem ? subItem : 1);
+ }
+ item->GetFocusedLayout()->Render(item, m_parentID, m_renderTime);
+ }
+ m_lastItem = item;
+ }
+ else
+ {
+ if (item->GetFocusedLayout())
+ item->GetFocusedLayout()->SetFocusedItem(0); // focus is not set
+ if (!item->GetLayout())
+ {
+ CGUIListItemLayout *layout = new CGUIListItemLayout(*m_layout);
+ item->SetLayout(layout);
+ }
+ if (item->GetFocusedLayout() && item->GetFocusedLayout()->IsAnimating(ANIM_TYPE_UNFOCUS))
+ item->GetFocusedLayout()->Render(item, m_parentID, m_renderTime);
+ else if (item->GetLayout())
+ item->GetLayout()->Render(item, m_parentID, m_renderTime);
+ }
+ g_graphicsContext.RestoreOrigin();
+}
+
+bool CGUIBaseContainer::OnAction(const CAction &action)
+{
+ if (action.id >= KEY_ASCII)
+ {
+ OnJumpLetter((char)(action.id & 0xff));
+ return true;
+ }
+
+ switch (action.id)
+ {
+ case ACTION_MOVE_LEFT:
+ case ACTION_MOVE_RIGHT:
+ case ACTION_MOVE_DOWN:
+ case ACTION_MOVE_UP:
+ {
+ if (!HasFocus()) return false;
+ if (action.holdTime > HOLD_TIME_START &&
+ ((m_orientation == VERTICAL && (action.id == ACTION_MOVE_UP || action.id == ACTION_MOVE_DOWN)) ||
+ (m_orientation == HORIZONTAL && (action.id == ACTION_MOVE_LEFT || action.id == ACTION_MOVE_RIGHT))))
+ { // action is held down - repeat a number of times
+ float speed = std::min(1.0f, (float)(action.holdTime - HOLD_TIME_START) / (HOLD_TIME_END - HOLD_TIME_START));
+ unsigned int itemsPerFrame = 1;
+ if (m_lastHoldTime) // number of rows/10 items/second max speed
+ itemsPerFrame = std::max((unsigned int)1, (unsigned int)(speed * 0.0001f * GetRows() * (timeGetTime() - m_lastHoldTime)));
+ m_lastHoldTime = timeGetTime();
+ if (action.id == ACTION_MOVE_LEFT || action.id == ACTION_MOVE_UP)
+ while (itemsPerFrame--) MoveUp(false);
+ else
+ while (itemsPerFrame--) MoveDown(false);
+ return true;
+ }
+ else
+ {
+ m_lastHoldTime = 0;
+ return CGUIControl::OnAction(action);
+ }
+ }
+ break;
+
+ case ACTION_FIRST_PAGE:
+ SelectItem(0);
+ return true;
+
+ case ACTION_LAST_PAGE:
+ if (m_items.size())
+ SelectItem(m_items.size() - 1);
+ return true;
+
+ case ACTION_NEXT_LETTER:
+ {
+ OnNextLetter();
+ return true;
+ }
+ break;
+ case ACTION_PREV_LETTER:
+ {
+ OnPrevLetter();
+ return true;
+ }
+ break;
+ case ACTION_JUMP_SMS2:
+ case ACTION_JUMP_SMS3:
+ case ACTION_JUMP_SMS4:
+ case ACTION_JUMP_SMS5:
+ case ACTION_JUMP_SMS6:
+ case ACTION_JUMP_SMS7:
+ case ACTION_JUMP_SMS8:
+ case ACTION_JUMP_SMS9:
+ {
+ OnJumpSMS(action.id - ACTION_JUMP_SMS2 + 2);
+ return true;
+ }
+ break;
+
+ default:
+ if (action.id)
+ {
+ return OnClick(action.id);
+ }
+ }
+ return false;
+}
+
+bool CGUIBaseContainer::OnMessage(CGUIMessage& message)
+{
+ if (message.GetControlId() == GetID() )
+ {
+ if (!m_staticContent)
+ {
+ if (message.GetMessage() == GUI_MSG_LABEL_BIND && message.GetPointer())
+ { // bind our items
+ Reset();
+ CFileItemList *items = (CFileItemList *)message.GetPointer();
+ for (int i = 0; i < items->Size(); i++)
+ m_items.push_back(items->Get(i));
+ UpdateLayout(true); // true to refresh all items
+ UpdateScrollByLetter();
+ SelectItem(message.GetParam1());
+ return true;
+ }
+ if (message.GetMessage() == GUI_MSG_LABEL_ADD && message.GetItem())
+ {
+ CGUIListItemPtr item = message.GetItem();
+ m_items.push_back(item);
+ UpdateScrollByLetter();
+ SetPageControlRange();
+ return true;
+ }
+ else if (message.GetMessage() == GUI_MSG_LABEL_RESET)
+ {
+ Reset();
+ SetPageControlRange();
+ return true;
+ }
+ }
+ if (message.GetMessage() == GUI_MSG_ITEM_SELECTED)
+ {
+ message.SetParam1(GetSelectedItem());
+ return true;
+ }
+ else if (message.GetMessage() == GUI_MSG_PAGE_CHANGE)
+ {
+ if (message.GetSenderId() == m_pageControl && IsVisible())
+ { // update our page if we're visible - not much point otherwise
+ if ((int)message.GetParam1() != m_offset)
+ m_pageChangeTimer.StartZero();
+ ScrollToOffset(message.GetParam1());
+ return true;
+ }
+ }
+ else if (message.GetMessage() == GUI_MSG_REFRESH_LIST)
+ { // update our list contents
+ for (unsigned int i = 0; i < m_items.size(); ++i)
+ m_items[i]->SetInvalid();
+ }
+ else if (message.GetMessage() == GUI_MSG_MOVE_OFFSET)
+ {
+ int count = (int)message.GetParam1();
+ while (count < 0)
+ {
+ MoveUp(true);
+ count++;
+ }
+ while (count > 0)
+ {
+ MoveDown(true);
+ count--;
+ }
+ return true;
+ }
+ }
+ return CGUIControl::OnMessage(message);
+}
+
+void CGUIBaseContainer::OnUp()
+{
+ bool wrapAround = m_controlUp == GetID() || !(m_controlUp || m_upActions.size());
+ if (m_orientation == VERTICAL && MoveUp(wrapAround))
+ return;
+ // with horizontal lists it doesn't make much sense to have multiselect labels
+ CGUIControl::OnUp();
+}
+
+void CGUIBaseContainer::OnDown()
+{
+ bool wrapAround = m_controlDown == GetID() || !(m_controlDown || m_downActions.size());
+ if (m_orientation == VERTICAL && MoveDown(wrapAround))
+ return;
+ // with horizontal lists it doesn't make much sense to have multiselect labels
+ CGUIControl::OnDown();
+}
+
+void CGUIBaseContainer::OnLeft()
+{
+ bool wrapAround = m_controlLeft == GetID() || !(m_controlLeft || m_leftActions.size());
+ if (m_orientation == HORIZONTAL && MoveUp(wrapAround))
+ return;
+ else if (m_orientation == VERTICAL)
+ {
+ CGUIListItemLayout *focusedLayout = GetFocusedLayout();
+ if (focusedLayout && focusedLayout->MoveLeft())
+ return;
+ }
+ CGUIControl::OnLeft();
+}
+
+void CGUIBaseContainer::OnRight()
+{
+ bool wrapAround = m_controlRight == GetID() || !(m_controlRight || m_rightActions.size());
+ if (m_orientation == HORIZONTAL && MoveDown(wrapAround))
+ return;
+ else if (m_orientation == VERTICAL)
+ {
+ CGUIListItemLayout *focusedLayout = GetFocusedLayout();
+ if (focusedLayout && focusedLayout->MoveRight())
+ return;
+ }
+ CGUIControl::OnRight();
+}
+
+void CGUIBaseContainer::OnNextLetter()
+{
+ int offset = CorrectOffset(m_offset, m_cursor);
+ for (unsigned int i = 0; i < m_letterOffsets.size(); i++)
+ {
+ if (m_letterOffsets[i].first > offset)
+ {
+ SelectItem(m_letterOffsets[i].first);
+ return;
+ }
+ }
+}
+
+void CGUIBaseContainer::OnPrevLetter()
+{
+ int offset = CorrectOffset(m_offset, m_cursor);
+ if (!m_letterOffsets.size())
+ return;
+ for (int i = (int)m_letterOffsets.size() - 1; i >= 0; i--)
+ {
+ if (m_letterOffsets[i].first < offset)
+ {
+ SelectItem(m_letterOffsets[i].first);
+ return;
+ }
+ }
+}
+
+void CGUIBaseContainer::OnJumpLetter(char letter)
+{
+ if (m_matchTimer.GetElapsedMilliseconds() < letter_match_timeout)
+ m_match.push_back(letter);
+ else
+ m_match.Format("%c", letter);
+
+ m_matchTimer.StartZero();
+
+ // we can't jump through letters if we have none
+ if (0 == m_letterOffsets.size())
+ return;
+
+ // find the current letter we're focused on
+ unsigned int offset = CorrectOffset(m_offset, m_cursor);
+ for (unsigned int i = (offset + 1) % m_items.size(); i != offset; i = (i+1) % m_items.size())
+ {
+ CGUIListItemPtr item = m_items[i];
+ if (0 == strnicmp(item->GetSortLabel().c_str(), m_match.c_str(), m_match.size()))
+ {
+ SelectItem(i);
+ return;
+ }
+ }
+ // no match found - repeat with a single letter
+ if (m_match.size() > 1)
+ {
+ m_match.clear();
+ OnJumpLetter(letter);
+ }
+}
+
+void CGUIBaseContainer::OnJumpSMS(int letter)
+{
+ static const char letterMap[8][6] = { "ABC2", "DEF3", "GHI4", "JKL5", "MNO6", "PQRS7", "TUV8", "WXYZ9" };
+
+ // only 2..9 supported
+ if (letter < 2 || letter > 9 || !m_letterOffsets.size())
+ return;
+
+ const CStdString letters = letterMap[letter - 2];
+ // find where we currently are
+ int offset = CorrectOffset(m_offset, m_cursor);
+ unsigned int currentLetter = 0;
+ while (currentLetter + 1 < m_letterOffsets.size() && m_letterOffsets[currentLetter + 1].first <= offset)
+ currentLetter++;
+
+ // now switch to the next letter
+ CStdString current = m_letterOffsets[currentLetter].second;
+ int startPos = (letters.Find(current) + 1) % letters.size();
+ // now jump to letters[startPos], or another one in the same range if possible
+ int pos = startPos;
+ while (true)
+ {
+ // check if we can jump to this letter
+ for (unsigned int i = 0; i < m_letterOffsets.size(); i++)
+ {
+ if (m_letterOffsets[i].second == letters.Mid(pos, 1))
+ {
+ SelectItem(m_letterOffsets[i].first);
+ return;
+ }
+ }
+ pos = (pos + 1) % letters.size();
+ if (pos == startPos)
+ return;
+ }
+}
+
+bool CGUIBaseContainer::MoveUp(bool wrapAround)
+{
+ return true;
+}
+
+bool CGUIBaseContainer::MoveDown(bool wrapAround)
+{
+ return true;
+}
+
+// scrolls the said amount
+void CGUIBaseContainer::Scroll(int amount)
+{
+ ScrollToOffset(m_offset + amount);
+}
+
+int CGUIBaseContainer::GetSelectedItem() const
+{
+ return CorrectOffset(m_offset, m_cursor);
+}
+
+CGUIListItemPtr CGUIBaseContainer::GetListItem(int offset, unsigned int flag) const
+{
+ if (!m_items.size())
+ return CGUIListItemPtr();
+ int item = GetSelectedItem() + offset;
+ if (flag & INFOFLAG_LISTITEM_POSITION) // use offset from the first item displayed, taking into account scrolling
+ item = CorrectOffset((int)(m_scrollOffset / m_layout->Size(m_orientation)), offset);
+
+ if (flag & INFOFLAG_LISTITEM_WRAP)
+ {
+ item %= ((int)m_items.size());
+ if (item < 0) item += m_items.size();
+ return m_items[item];
+ }
+ else
+ {
+ if (item >= 0 && item < (int)m_items.size())
+ return m_items[item];
+ }
+ return CGUIListItemPtr();
+}
+
+CGUIListItemLayout *CGUIBaseContainer::GetFocusedLayout() const
+{
+ CGUIListItemPtr item = GetListItem(0);
+ if (item.get()) return item->GetFocusedLayout();
+ return NULL;
+}
+
+bool CGUIBaseContainer::SelectItemFromPoint(const CPoint &point)
+{
+ if (!m_focusedLayout || !m_layout)
+ return false;
+
+ int row = 0;
+ float pos = (m_orientation == VERTICAL) ? point.y : point.x;
+ while (row < m_itemsPerPage + 1) // 1 more to ensure we get the (possible) half item at the end.
+ {
+ const CGUIListItemLayout *layout = (row == m_cursor) ? m_focusedLayout : m_layout;
+ if (pos < layout->Size(m_orientation) && row + m_offset < (int)m_items.size())
+ { // found correct "row" -> check horizontal
+ if (!InsideLayout(layout, point))
+ return false;
+
+ MoveToItem(row);
+ CGUIListItemLayout *focusedLayout = GetFocusedLayout();
+ if (focusedLayout)
+ {
+ CPoint pt(point);
+ if (m_orientation == VERTICAL)
+ pt.y = pos;
+ else
+ pt.x = pos;
+ focusedLayout->SelectItemFromPoint(pt);
+ }
+ return true;
+ }
+ row++;
+ pos -= layout->Size(m_orientation);
+ }
+ return false;
+}
+
+bool CGUIBaseContainer::OnMouseOver(const CPoint &point)
+{
+ // select the item under the pointer
+ SelectItemFromPoint(point - CPoint(m_posX, m_posY));
+ return CGUIControl::OnMouseOver(point);
+}
+
+bool CGUIBaseContainer::OnMouseClick(int button, const CPoint &point)
+{
+ if (SelectItemFromPoint(point - CPoint(m_posX, m_posY)))
+ { // send click message to window
+ OnClick(ACTION_MOUSE_CLICK + button);
+ return true;
+ }
+ return false;
+}
+
+bool CGUIBaseContainer::OnMouseDoubleClick(int button, const CPoint &point)
+{
+ if (SelectItemFromPoint(point - CPoint(m_posX, m_posY)))
+ { // send double click message to window
+ OnClick(ACTION_MOUSE_DOUBLE_CLICK + button);
+ return true;
+ }
+ return false;
+}
+
+bool CGUIBaseContainer::OnClick(int actionID)
+{
+ int subItem = 0;
+ if (actionID == ACTION_SELECT_ITEM || actionID == ACTION_MOUSE_LEFT_CLICK)
+ {
+ if (m_staticContent)
+ { // "select" action
+ int selected = GetSelectedItem();
+ if (selected >= 0 && selected < (int)m_items.size())
+ {
+ CFileItemPtr item = boost::static_pointer_cast<CFileItem>(m_items[selected]);
+ // multiple action strings are concat'd together, separated with " , "
+ vector<CStdString> actions;
+ StringUtils::SplitString(item->m_strPath, " , ", actions);
+ for (unsigned int i = 0; i < actions.size(); i++)
+ {
+ CStdString action = actions[i];
+ action.Replace(",,", ",");
+ CGUIMessage message(GUI_MSG_EXECUTE, GetID(), GetParentID());
+ message.SetStringParam(action);
+ g_graphicsContext.SendMessage(message);
+ }
+ }
+ return true;
+ }
+ // grab the currently focused subitem (if applicable)
+ CGUIListItemLayout *focusedLayout = GetFocusedLayout();
+ if (focusedLayout)
+ subItem = focusedLayout->GetFocusedItem();
+ }
+ // Don't know what to do, so send to our parent window.
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID(), actionID, subItem);
+ return SendWindowMessage(msg);
+}
+
+bool CGUIBaseContainer::OnMouseWheel(char wheel, const CPoint &point)
+{
+ Scroll(-wheel);
+ return true;
+}
+
+CStdString CGUIBaseContainer::GetDescription() const
+{
+ CStdString strLabel;
+ int item = GetSelectedItem();
+ if (item >= 0 && item < (int)m_items.size())
+ {
+ CGUIListItemPtr pItem = m_items[item];
+ if (pItem->m_bIsFolder)
+ strLabel.Format("[%s]", pItem->GetLabel().c_str());
+ else
+ strLabel = pItem->GetLabel();
+ }
+ return strLabel;
+}
+
+void CGUIBaseContainer::SetFocus(bool bOnOff)
+{
+ if (bOnOff != HasFocus())
+ {
+ SetInvalid();
+ m_lastItem = NULL;
+ }
+ CGUIControl::SetFocus(bOnOff);
+}
+
+void CGUIBaseContainer::SaveStates(vector<CControlState> &states)
+{
+ states.push_back(CControlState(GetID(), GetSelectedItem()));
+}
+
+void CGUIBaseContainer::SetPageControl(int id)
+{
+ m_pageControl = id;
+}
+
+void CGUIBaseContainer::ValidateOffset()
+{
+}
+
+void CGUIBaseContainer::DoRender(DWORD currentTime)
+{
+ m_renderTime = currentTime;
+ CGUIControl::DoRender(currentTime);
+ if (m_pageChangeTimer.GetElapsedMilliseconds() > 200)
+ m_pageChangeTimer.Stop();
+ m_wasReset = false;
+}
+
+void CGUIBaseContainer::AllocResources()
+{
+ CalculateLayout();
+}
+
+void CGUIBaseContainer::FreeResources()
+{
+ CGUIControl::FreeResources();
+ if (m_staticContent)
+ { // free any static content
+ Reset();
+ m_staticItems.clear();
+ }
+ m_scrollSpeed = 0;
+}
+
+void CGUIBaseContainer::UpdateLayout(bool updateAllItems)
+{
+ if (updateAllItems)
+ { // free memory of items
+ for (iItems it = m_items.begin(); it != m_items.end(); it++)
+ (*it)->FreeMemory();
+ }
+ // and recalculate the layout
+ CalculateLayout();
+ SetPageControlRange();
+}
+
+void CGUIBaseContainer::SetPageControlRange()
+{
+ if (m_pageControl)
+ {
+ CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), m_pageControl, m_itemsPerPage, GetRows());
+ SendWindowMessage(msg);
+ }
+}
+
+void CGUIBaseContainer::UpdatePageControl(int offset)
+{
+ if (m_pageControl)
+ { // tell our pagecontrol (scrollbar or whatever) to update (offset it by our cursor position)
+ CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), m_pageControl, offset);
+ SendWindowMessage(msg);
+ }
+}
+
+void CGUIBaseContainer::UpdateVisibility(const CGUIListItem *item)
+{
+ CGUIControl::UpdateVisibility(item);
+
+ if (!IsVisible())
+ return; // no need to update the content if we're not visible
+
+ // check whether we need to update our layouts
+ if ((m_layout && m_layout->GetCondition() && !g_infoManager.GetBool(m_layout->GetCondition(), GetParentID())) ||
+ (m_focusedLayout && m_focusedLayout->GetCondition() && !g_infoManager.GetBool(m_focusedLayout->GetCondition(), GetParentID())))
+ {
+ // and do it
+ int item = GetSelectedItem();
+ UpdateLayout(true); // true to refresh all items
+ SelectItem(item);
+ }
+
+ if (m_staticContent)
+ { // update our item list with our new content, but only add those items that should
+ // be visible. Save the previous item and keep it if we are adding that one.
+ CGUIListItem *lastItem = m_lastItem;
+ Reset();
+ bool updateItems = false;
+ if (!m_staticUpdateTime)
+ m_staticUpdateTime = timeGetTime();
+ if (timeGetTime() - m_staticUpdateTime > 1000)
+ {
+ m_staticUpdateTime = timeGetTime();
+ updateItems = true;
+ }
+ for (unsigned int i = 0; i < m_staticItems.size(); ++i)
+ {
+ CFileItemPtr item = boost::static_pointer_cast<CFileItem>(m_staticItems[i]);
+ // m_idepth is used to store the visibility condition
+ if (!item->m_idepth || g_infoManager.GetBool(item->m_idepth, GetParentID()))
+ {
+ m_items.push_back(item);
+ if (item.get() == lastItem)
+ m_lastItem = lastItem;
+ }
+ if (updateItems && item->HasProperties())
+ { // has info, so update it
+ CStdString info = item->GetProperty("label");
+ if (!info.IsEmpty()) item->SetLabel(CGUIInfoLabel::GetLabel(info));
+ info = item->GetProperty("label2");
+ if (!info.IsEmpty()) item->SetLabel2(CGUIInfoLabel::GetLabel(info));
+ info = item->GetProperty("icon");
+ if (!info.IsEmpty()) item->SetIconImage(CGUIInfoLabel::GetLabel(info, true));
+ info = item->GetProperty("thumb");
+ if (!info.IsEmpty()) item->SetThumbnailImage(CGUIInfoLabel::GetLabel(info, true));
+ }
+ }
+ UpdateScrollByLetter();
+ }
+}
+
+void CGUIBaseContainer::CalculateLayout()
+{
+ CGUIListItemLayout *oldFocusedLayout = m_focusedLayout;
+ CGUIListItemLayout *oldLayout = m_layout;
+ GetCurrentLayouts();
+
+ // calculate the number of items to display
+ assert(m_focusedLayout && m_layout);
+ if (!m_focusedLayout || !m_layout) return;
+
+ if (oldLayout == m_layout && oldFocusedLayout == m_focusedLayout)
+ return; // nothing has changed, so don't update stuff
+
+ m_itemsPerPage = (int)((Size() - m_focusedLayout->Size(m_orientation)) / m_layout->Size(m_orientation)) + 1;
+
+ // ensure that the scroll offset is a multiple of our size
+ m_scrollOffset = m_offset * m_layout->Size(m_orientation);
+}
+
+void CGUIBaseContainer::UpdateScrollByLetter()
+{
+ m_letterOffsets.clear();
+
+ // for scrolling by letter we have an offset table into our vector.
+ CStdString currentMatch;
+ for (unsigned int i = 0; i < m_items.size(); i++)
+ {
+ CGUIListItemPtr item = m_items[i];
+ // The letter offset jumping is only for ASCII characters at present, and
+ // our checks are all done in uppercase
+ CStdString nextLetter = item->GetSortLabel().Left(1);
+ nextLetter.ToUpper();
+ if (currentMatch != nextLetter)
+ {
+ currentMatch = nextLetter;
+ m_letterOffsets.push_back(make_pair((int)i, currentMatch));
+ }
+ }
+}
+
+unsigned int CGUIBaseContainer::GetRows() const
+{
+ return m_items.size();
+}
+
+inline float CGUIBaseContainer::Size() const
+{
+ return (m_orientation == HORIZONTAL) ? m_width : m_height;
+}
+
+#define MAX_SCROLL_AMOUNT 0.4f
+
+void CGUIBaseContainer::ScrollToOffset(int offset)
+{
+ float size = m_layout->Size(m_orientation);
+ int range = m_itemsPerPage / 4;
+ if (range <= 0) range = 1;
+ if (offset * size < m_scrollOffset && m_scrollOffset - offset * size > size * range)
+ { // scrolling up, and we're jumping more than 0.5 of a screen
+ m_scrollOffset = (offset + range) * size;
+ }
+ if (offset * size > m_scrollOffset && offset * size - m_scrollOffset > size * range)
+ { // scrolling down, and we're jumping more than 0.5 of a screen
+ m_scrollOffset = (offset - range) * size;
+ }
+ m_scrollSpeed = (offset * size - m_scrollOffset) / m_scrollTime;
+ if (!m_wasReset)
+ {
+ g_infoManager.SetContainerMoving(GetID(), offset - m_offset);
+ if (m_scrollSpeed)
+ m_scrollTimer.Start();
+ else
+ m_scrollTimer.Stop();
+ }
+ m_offset = offset;
+}
+
+void CGUIBaseContainer::UpdateScrollOffset()
+{
+ m_scrollOffset += m_scrollSpeed * (m_renderTime - m_scrollLastTime);
+ if ((m_scrollSpeed < 0 && m_scrollOffset < m_offset * m_layout->Size(m_orientation)) ||
+ (m_scrollSpeed > 0 && m_scrollOffset > m_offset * m_layout->Size(m_orientation)))
+ {
+ m_scrollOffset = m_offset * m_layout->Size(m_orientation);
+ m_scrollSpeed = 0;
+ m_scrollTimer.Stop();
+ }
+ m_scrollLastTime = m_renderTime;
+}
+
+int CGUIBaseContainer::CorrectOffset(int offset, int cursor) const
+{
+ return offset + cursor;
+}
+
+void CGUIBaseContainer::Reset()
+{
+ m_wasReset = true;
+ m_items.clear();
+ m_lastItem = NULL;
+}
+
+void CGUIBaseContainer::LoadLayout(TiXmlElement *layout)
+{
+ TiXmlElement *itemElement = layout->FirstChildElement("itemlayout");
+ while (itemElement)
+ { // we have a new item layout
+ CGUIListItemLayout itemLayout;
+ itemLayout.LoadLayout(itemElement, false);
+ m_layouts.push_back(itemLayout);
+ itemElement = itemElement->NextSiblingElement("itemlayout");
+ }
+ itemElement = layout->FirstChildElement("focusedlayout");
+ while (itemElement)
+ { // we have a new item layout
+ CGUIListItemLayout itemLayout;
+ itemLayout.LoadLayout(itemElement, true);
+ m_focusedLayouts.push_back(itemLayout);
+ itemElement = itemElement->NextSiblingElement("focusedlayout");
+ }
+}
+
+void CGUIBaseContainer::LoadContent(TiXmlElement *content)
+{
+ TiXmlElement *root = content->FirstChildElement("content");
+ if (!root)
+ return;
+
+ g_SkinInfo.ResolveIncludes(root);
+
+ vector<CGUIListItemPtr> items;
+ TiXmlElement *item = root->FirstChildElement("item");
+ while (item)
+ {
+ // format:
+ // <item label="Cool Video" label2="" thumb="mythumb.png">PlayMedia(c:\videos\cool_video.avi)</item>
+ // <item label="My Album" label2="" thumb="whatever.jpg">ActivateWindow(MyMusic,c:\music\my album)</item>
+ // <item label="Apple Movie Trailers" label2="Bob" thumb="foo.tbn">RunScript(special://xbmc/scripts/apple movie trailers/default.py)</item>
+
+ // OR the more verbose, but includes-friendly:
+ // <item>
+ // <label>blah</label>
+ // <label2>foo</label2>
+ // <thumb>bar.png</thumb>
+ // <icon>foo.jpg</icon>
+ // <onclick>ActivateWindow(Home)</onclick>
+ // </item>
+ g_SkinInfo.ResolveIncludes(item);
+ if (item->FirstChild())
+ {
+ CFileItemPtr newItem;
+ // check whether we're using the more verbose method...
+ TiXmlNode *click = item->FirstChild("onclick");
+ if (click && click->FirstChild())
+ {
+ CStdString label, label2, thumb, icon;
+ XMLUtils::GetString(item, "label", label); label = CGUIControlFactory::FilterLabel(label);
+ XMLUtils::GetString(item, "label2", label2); label2 = CGUIControlFactory::FilterLabel(label2);
+ XMLUtils::GetString(item, "thumb", thumb); thumb = CGUIControlFactory::FilterLabel(thumb);
+ XMLUtils::GetString(item, "icon", icon); icon = CGUIControlFactory::FilterLabel(icon);
+ const char *id = item->Attribute("id");
+ int visibleCondition = 0;
+ CGUIControlFactory::GetConditionalVisibility(item, visibleCondition);
+ newItem.reset(new CFileItem(CGUIInfoLabel::GetLabel(label)));
+ // multiple action strings are concat'd together, separated with " , "
+ vector<CGUIActionDescriptor> actions;
+ CGUIControlFactory::GetMultipleString(item, "onclick", actions);
+ newItem->m_strPath = "";
+ for (vector<CGUIActionDescriptor>::iterator it = actions.begin(); it != actions.end(); ++it)
+ {
+ (*it).m_action.Replace(",", ",,");
+ if (newItem->m_strPath.length() > 0)
+ {
+ newItem->m_strPath += " , ";
+ }
+ newItem->m_strPath += (*it).m_action;
+ }
+ newItem->SetLabel2(CGUIInfoLabel::GetLabel(label2));
+ newItem->SetThumbnailImage(CGUIInfoLabel::GetLabel(thumb, true));
+ newItem->SetIconImage(CGUIInfoLabel::GetLabel(icon, true));
+ if (label.Find("$INFO") >= 0) newItem->SetProperty("label", label);
+ if (label2.Find("$INFO") >= 0) newItem->SetProperty("label2", label2);
+ if (icon.Find("$INFO") >= 0) newItem->SetProperty("icon", icon);
+ if (thumb.Find("$INFO") >= 0) newItem->SetProperty("thumb", thumb);
+ if (id) newItem->m_iprogramCount = atoi(id);
+ newItem->m_idepth = visibleCondition;
+ }
+ else
+ {
+ CStdString label, label2, thumb, icon;
+ label = item->Attribute("label"); label = CGUIControlFactory::FilterLabel(label);
+ label2 = item->Attribute("label2"); label2 = CGUIControlFactory::FilterLabel(label2);
+ thumb = item->Attribute("thumb"); thumb = CGUIControlFactory::FilterLabel(thumb);
+ icon = item->Attribute("icon"); icon = CGUIControlFactory::FilterLabel(icon);
+ const char *id = item->Attribute("id");
+ newItem.reset(new CFileItem(CGUIInfoLabel::GetLabel(label)));
+ newItem->m_strPath = item->FirstChild()->Value();
+ newItem->SetLabel2(CGUIInfoLabel::GetLabel(label2));
+ newItem->SetThumbnailImage(CGUIInfoLabel::GetLabel(thumb, true));
+ newItem->SetIconImage(CGUIInfoLabel::GetLabel(icon, true));
+ if (id) newItem->m_iprogramCount = atoi(id);
+ newItem->m_idepth = 0; // no visibility condition
+ }
+ items.push_back(newItem);
+ }
+ item = item->NextSiblingElement("item");
+ }
+ SetStaticContent(items);
+}
+
+void CGUIBaseContainer::SetStaticContent(const vector<CGUIListItemPtr> &items)
+{
+ m_staticContent = true;
+ m_staticUpdateTime = 0;
+ m_staticItems.clear();
+ m_staticItems.assign(items.begin(), items.end());
+ UpdateVisibility();
+}
+
+void CGUIBaseContainer::SetType(VIEW_TYPE type, const CStdString &label)
+{
+ m_type = type;
+ m_label = label;
+}
+
+void CGUIBaseContainer::MoveToItem(int item)
+{
+ g_infoManager.SetContainerMoving(GetID(), item - m_cursor);
+ m_cursor = item;
+}
+
+void CGUIBaseContainer::FreeMemory(int keepStart, int keepEnd)
+{
+ if (keepStart < keepEnd)
+ { // remove before keepStart and after keepEnd
+ for (int i = 0; i < keepStart && i < (int)m_items.size(); ++i)
+ m_items[i]->FreeMemory();
+ for (int i = keepEnd + 1; i < (int)m_items.size(); ++i)
+ m_items[i]->FreeMemory();
+ }
+ else
+ { // wrapping
+ for (int i = keepEnd + 1; i < keepStart && i < (int)m_items.size(); ++i)
+ m_items[i]->FreeMemory();
+ }
+}
+
+bool CGUIBaseContainer::InsideLayout(const CGUIListItemLayout *layout, const CPoint &point)
+{
+ if (!layout) return false;
+ if ((m_orientation == VERTICAL && layout->Size(HORIZONTAL) && point.x > layout->Size(HORIZONTAL)) ||
+ (m_orientation == HORIZONTAL && layout->Size(VERTICAL) && point.y > layout->Size(VERTICAL)))
+ return false;
+ return true;
+}
+
+#ifdef _DEBUG
+void CGUIBaseContainer::DumpTextureUse()
+{
+ CLog::Log(LOGDEBUG, "%s for container %u", __FUNCTION__, GetID());
+ for (unsigned int i = 0; i < m_items.size(); ++i)
+ {
+ CGUIListItemPtr item = m_items[i];
+ if (item->GetFocusedLayout()) item->GetFocusedLayout()->DumpTextureUse();
+ if (item->GetLayout()) item->GetLayout()->DumpTextureUse();
+ }
+}
+#endif
+
+bool CGUIBaseContainer::GetCondition(int condition, int data) const
+{
+ switch (condition)
+ {
+ case CONTAINER_ROW:
+ return (m_orientation == VERTICAL) ? (m_cursor == data) : true;
+ case CONTAINER_COLUMN:
+ return (m_orientation == HORIZONTAL) ? (m_cursor == data) : true;
+ case CONTAINER_POSITION:
+ return (m_cursor == data);
+ case CONTAINER_HAS_NEXT:
+ return (HasNextPage());
+ case CONTAINER_HAS_PREVIOUS:
+ return (HasPreviousPage());
+ case CONTAINER_SUBITEM:
+ {
+ CGUIListItemLayout *layout = GetFocusedLayout();
+ return layout ? (layout->GetFocusedItem() == (unsigned int)data) : false;
+ }
+ case CONTAINER_SCROLLING:
+ return (m_scrollTimer.GetElapsedMilliseconds() > m_scrollTime || m_pageChangeTimer.IsRunning());
+ default:
+ return false;
+ }
+}
+
+void CGUIBaseContainer::GetCurrentLayouts()
+{
+ m_layout = NULL;
+ for (unsigned int i = 0; i < m_layouts.size(); i++)
+ {
+ int condition = m_layouts[i].GetCondition();
+ if (!condition || g_infoManager.GetBool(condition, GetParentID()))
+ {
+ m_layout = &m_layouts[i];
+ break;
+ }
+ }
+ if (!m_layout && m_layouts.size())
+ m_layout = &m_layouts[0]; // failsafe
+
+ m_focusedLayout = NULL;
+ for (unsigned int i = 0; i < m_focusedLayouts.size(); i++)
+ {
+ int condition = m_focusedLayouts[i].GetCondition();
+ if (!condition || g_infoManager.GetBool(condition, GetParentID()))
+ {
+ m_focusedLayout = &m_focusedLayouts[i];
+ break;
+ }
+ }
+ if (!m_focusedLayout && m_focusedLayouts.size())
+ m_focusedLayout = &m_focusedLayouts[0]; // failsafe
+}
+
+bool CGUIBaseContainer::HasNextPage() const
+{
+ return false;
+}
+
+bool CGUIBaseContainer::HasPreviousPage() const
+{
+ return false;
+}
+
+CStdString CGUIBaseContainer::GetLabel(int info) const
+{
+ CStdString label;
+ switch (info)
+ {
+ case CONTAINER_NUM_PAGES:
+ label.Format("%u", (GetRows() + m_itemsPerPage - 1) / m_itemsPerPage);
+ break;
+ case CONTAINER_CURRENT_PAGE:
+ label.Format("%u", GetCurrentPage());
+ break;
+ case CONTAINER_POSITION:
+ label.Format("%i", m_cursor);
+ break;
+ case CONTAINER_NUM_ITEMS:
+ {
+ unsigned int numItems = GetNumItems();
+ if (numItems && m_items[0]->IsFileItem() && (boost::static_pointer_cast<CFileItem>(m_items[0]))->IsParentFolder())
+ label.Format("%u", numItems-1);
+ else
+ label.Format("%u", numItems);
+ }
+ break;
+ default:
+ break;
+ }
+ return label;
+}
+
+int CGUIBaseContainer::GetCurrentPage() const
+{
+ if (m_offset + m_itemsPerPage >= (int)GetRows()) // last page
+ return (GetRows() + m_itemsPerPage - 1) / m_itemsPerPage;
+ return m_offset / m_itemsPerPage + 1;
+}
+
+void CGUIBaseContainer::GetCacheOffsets(int &cacheBefore, int &cacheAfter)
+{
+ if (m_scrollSpeed > 0)
+ {
+ cacheBefore = 0;
+ cacheAfter = m_cacheItems;
+ }
+ else if (m_scrollSpeed < 0)
+ {
+ cacheBefore = m_cacheItems;
+ cacheAfter = 0;
+ }
+ else
+ {
+ cacheBefore = m_cacheItems / 2;
+ cacheAfter = m_cacheItems / 2;
+ }
+}
diff --git a/guilib/GUIBaseContainer.h b/guilib/GUIBaseContainer.h
new file mode 100644
index 0000000000..7a0fe0cd2d
--- /dev/null
+++ b/guilib/GUIBaseContainer.h
@@ -0,0 +1,181 @@
+/*!
+\file GUIListContainer.h
+\brief
+*/
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+#include "GUIListItemLayout.h"
+#include "boost/shared_ptr.hpp"
+#include "utils/Stopwatch.h"
+
+typedef boost::shared_ptr<CGUIListItem> CGUIListItemPtr;
+
+/*!
+ \ingroup controls
+ \brief
+ */
+
+class CGUIBaseContainer : public CGUIControl
+{
+public:
+ CGUIBaseContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, int scrollTime, int preloadItems);
+ virtual ~CGUIBaseContainer(void);
+
+ virtual bool OnAction(const CAction &action);
+ virtual void OnDown();
+ virtual void OnUp();
+ virtual void OnLeft();
+ virtual void OnRight();
+ virtual bool OnMouseOver(const CPoint &point);
+ virtual bool OnMouseClick(int button, const CPoint &point);
+ virtual bool OnMouseDoubleClick(int button, const CPoint &point);
+ virtual bool OnMouseWheel(char wheel, const CPoint &point);
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual void SetFocus(bool bOnOff);
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void UpdateVisibility(const CGUIListItem *item = NULL);
+
+ virtual unsigned int GetRows() const;
+
+ virtual bool HasNextPage() const;
+ virtual bool HasPreviousPage() const;
+
+ void SetPageControl(int id);
+
+ virtual CStdString GetDescription() const;
+ virtual void SaveStates(std::vector<CControlState> &states);
+ virtual int GetSelectedItem() const;
+
+ virtual void DoRender(DWORD currentTime);
+ void LoadLayout(TiXmlElement *layout);
+ void LoadContent(TiXmlElement *content);
+
+ VIEW_TYPE GetType() const { return m_type; };
+ const CStdString &GetLabel() const { return m_label; };
+ void SetType(VIEW_TYPE type, const CStdString &label);
+
+ virtual bool IsContainer() const { return true; };
+ CGUIListItemPtr GetListItem(int offset, unsigned int flag = 0) const;
+
+ virtual bool GetCondition(int condition, int data) const;
+ CStdString GetLabel(int info) const;
+
+ void SetStaticContent(const std::vector<CGUIListItemPtr> &items);
+
+#ifdef _DEBUG
+ virtual void DumpTextureUse();
+#endif
+protected:
+ bool OnClick(int actionID);
+ virtual bool SelectItemFromPoint(const CPoint &point);
+ virtual void Render();
+ virtual void RenderItem(float posX, float posY, CGUIListItem *item, bool focused);
+ virtual void Scroll(int amount);
+ virtual bool MoveDown(bool wrapAround);
+ virtual bool MoveUp(bool wrapAround);
+ virtual void MoveToItem(int item);
+ virtual void ValidateOffset();
+ virtual int CorrectOffset(int offset, int cursor) const;
+ virtual void UpdateLayout(bool refreshAllItems = false);
+ virtual void SetPageControlRange();
+ virtual void UpdatePageControl(int offset);
+ virtual void CalculateLayout();
+ virtual void SelectItem(int item) {};
+ virtual void Reset();
+ virtual unsigned int GetNumItems() const { return m_items.size(); };
+ virtual int GetCurrentPage() const;
+ bool InsideLayout(const CGUIListItemLayout *layout, const CPoint &point);
+
+ inline float Size() const;
+ void MoveToRow(int row);
+ void FreeMemory(int keepStart, int keepEnd);
+ void GetCurrentLayouts();
+ CGUIListItemLayout *GetFocusedLayout() const;
+
+ int m_offset;
+ int m_cursor;
+ float m_analogScrollCount;
+ unsigned int m_lastHoldTime;
+
+ ORIENTATION m_orientation;
+ int m_itemsPerPage;
+
+ std::vector< CGUIListItemPtr > m_items;
+ typedef std::vector<CGUIListItemPtr> ::iterator iItems;
+ CGUIListItem *m_lastItem;
+
+ int m_pageControl;
+
+ DWORD m_renderTime;
+
+ std::vector<CGUIListItemLayout> m_layouts;
+ std::vector<CGUIListItemLayout> m_focusedLayouts;
+
+ CGUIListItemLayout *m_layout;
+ CGUIListItemLayout *m_focusedLayout;
+
+ virtual void ScrollToOffset(int offset);
+ void UpdateScrollOffset();
+
+ DWORD m_scrollLastTime;
+ int m_scrollTime;
+ float m_scrollOffset;
+
+ VIEW_TYPE m_type;
+ CStdString m_label;
+
+ bool m_staticContent;
+ DWORD m_staticUpdateTime;
+ std::vector<CGUIListItemPtr> m_staticItems;
+ bool m_wasReset; // true if we've received a Reset message until we've rendered once. Allows
+ // us to make sure we don't tell the infomanager that we've been moving when
+ // the "movement" was simply due to the list being repopulated (thus cursor position
+ // changing around)
+
+ void UpdateScrollByLetter();
+ void GetCacheOffsets(int &cacheBefore, int &cacheAfter);
+ bool ScrollingDown() const { return m_scrollSpeed > 0; };
+ bool ScrollingUp() const { return m_scrollSpeed < 0; };
+ void OnNextLetter();
+ void OnPrevLetter();
+ void OnJumpLetter(char letter);
+ void OnJumpSMS(int letter);
+ std::vector< std::pair<int, CStdString> > m_letterOffsets;
+private:
+ int m_cacheItems;
+ float m_scrollSpeed;
+ CStopWatch m_scrollTimer;
+ CStopWatch m_pageChangeTimer;
+
+ // letter match searching
+ CStopWatch m_matchTimer;
+ CStdString m_match;
+
+ static const int letter_match_timeout = 1000;
+};
+
+
diff --git a/guilib/GUIBorderedImage.cpp b/guilib/GUIBorderedImage.cpp
new file mode 100644
index 0000000000..6ba1c3d931
--- /dev/null
+++ b/guilib/GUIBorderedImage.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIBorderedImage.h"
+
+CGUIBorderedImage::CGUIBorderedImage(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& texture, const CTextureInfo& borderTexture, const FRECT &borderSize)
+ : CGUIImage(parentID, controlID, posX + borderSize.left, posY + borderSize.top, width - borderSize.left - borderSize.right, height - borderSize.top - borderSize.bottom, texture),
+ m_borderImage(posX, posY, width, height, borderTexture)
+{
+ memcpy(&m_borderSize, &borderSize, sizeof(FRECT));
+ ControlType = GUICONTROL_BORDEREDIMAGE;
+}
+
+CGUIBorderedImage::CGUIBorderedImage(const CGUIBorderedImage &right)
+: CGUIImage(right), m_borderImage(right.m_borderImage)
+{
+ memcpy(&m_borderSize, &right.m_borderSize, sizeof(FRECT));
+ ControlType = GUICONTROL_BORDEREDIMAGE;
+}
+
+CGUIBorderedImage::~CGUIBorderedImage(void)
+{
+}
+
+void CGUIBorderedImage::Render()
+{
+ if (!m_borderImage.GetFileName().IsEmpty() && m_texture.IsAllocated())
+ {
+ CRect rect = CRect(m_texture.GetXPosition(), m_texture.GetYPosition(), m_texture.GetXPosition() + m_texture.GetWidth(), m_texture.GetYPosition() + m_texture.GetHeight());
+ rect.Intersect(m_texture.GetRenderRect());
+ m_borderImage.SetPosition(rect.x1 - m_borderSize.left, rect.y1 - m_borderSize.top);
+ m_borderImage.SetWidth(rect.Width() + m_borderSize.left + m_borderSize.right);
+ m_borderImage.SetHeight(rect.Height() + m_borderSize.top + m_borderSize.bottom);
+ m_borderImage.Render();
+ }
+ CGUIImage::Render();
+}
+
+void CGUIBorderedImage::AllocResources()
+{
+ m_borderImage.AllocResources();
+ CGUIImage::AllocResources();
+}
+
+void CGUIBorderedImage::FreeResources()
+{
+ m_borderImage.FreeResources();
+ CGUIImage::FreeResources();
+}
+
+void CGUIBorderedImage::DynamicResourceAlloc(bool bOnOff)
+{
+ m_borderImage.DynamicResourceAlloc(bOnOff);
+ CGUIImage::DynamicResourceAlloc(bOnOff);
+}
diff --git a/guilib/GUIBorderedImage.h b/guilib/GUIBorderedImage.h
new file mode 100644
index 0000000000..535b1a00d6
--- /dev/null
+++ b/guilib/GUIBorderedImage.h
@@ -0,0 +1,47 @@
+#ifndef CGUIBorderedImage_H
+#define CGUIBorderedImage_H
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+#include "TextureManager.h"
+#include "GUIImage.h"
+
+class CGUIBorderedImage : public CGUIImage
+{
+public:
+ CGUIBorderedImage(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& texture, const CTextureInfo& borderTexture, const FRECT &borderSize);
+ CGUIBorderedImage(const CGUIBorderedImage &right);
+ virtual ~CGUIBorderedImage(void);
+ virtual CGUIBorderedImage *Clone() const { return new CGUIBorderedImage(*this); };
+
+ virtual void Render();
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+
+protected:
+ CGUITexture m_borderImage;
+ FRECT m_borderSize;
+};
+
+#endif
diff --git a/guilib/GUIButtonControl.cpp b/guilib/GUIButtonControl.cpp
new file mode 100644
index 0000000000..6c52bb7991
--- /dev/null
+++ b/guilib/GUIButtonControl.cpp
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIButtonControl.h"
+#include "GUIWindowManager.h"
+#include "GUIDialog.h"
+#include "utils/CharsetConverter.h"
+#include "GUIFontManager.h"
+#include "MouseStat.h"
+
+using namespace std;
+
+CGUIButtonControl::CGUIButtonControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus, const CLabelInfo& labelInfo)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+ , m_imgFocus(posX, posY, width, height, textureFocus)
+ , m_imgNoFocus(posX, posY, width, height, textureNoFocus)
+ , m_textLayout(labelInfo.font, false), m_textLayout2(labelInfo.font, false)
+{
+ m_bSelected = false;
+ m_alpha = 255;
+ m_dwFocusCounter = 0;
+ m_label = labelInfo;
+ ControlType = GUICONTROL_BUTTON;
+}
+
+CGUIButtonControl::~CGUIButtonControl(void)
+{
+}
+
+void CGUIButtonControl::Render()
+{
+ if (m_bInvalidated)
+ {
+ m_imgFocus.SetWidth(m_width);
+ m_imgFocus.SetHeight(m_height);
+
+ m_imgNoFocus.SetWidth(m_width);
+ m_imgNoFocus.SetHeight(m_height);
+ }
+
+ if (HasFocus())
+ {
+ if (m_pulseOnSelect)
+ {
+ DWORD dwAlphaCounter = m_dwFocusCounter + 2;
+ DWORD dwAlphaChannel;
+ if ((dwAlphaCounter % 128) >= 64)
+ dwAlphaChannel = dwAlphaCounter % 64;
+ else
+ dwAlphaChannel = 63 - (dwAlphaCounter % 64);
+
+ dwAlphaChannel += 192;
+ dwAlphaChannel = (DWORD)((float)m_alpha * (float)dwAlphaChannel / 255.0f);
+ m_imgFocus.SetAlpha((unsigned char)dwAlphaChannel);
+ }
+ m_imgFocus.SetVisible(true);
+ m_imgNoFocus.SetVisible(false);
+ m_dwFocusCounter++;
+ }
+ else
+ {
+ m_imgFocus.SetVisible(false);
+ m_imgNoFocus.SetVisible(true);
+ }
+ // render both so the visibility settings cause the frame counter to resetcorrectly
+ m_imgFocus.Render();
+ m_imgNoFocus.Render();
+
+ RenderText();
+ CGUIControl::Render();
+}
+
+void CGUIButtonControl::RenderText()
+{
+ m_textLayout.Update(m_info.GetLabel(m_parentID));
+
+ float fPosX = m_posX + m_label.offsetX;
+ float fPosY = m_posY + m_label.offsetY;
+
+ if (m_label.align & XBFONT_RIGHT)
+ fPosX = m_posX + m_width - m_label.offsetX;
+
+ if (m_label.align & XBFONT_CENTER_X)
+ fPosX = m_posX + m_width / 2;
+
+ if (m_label.align & XBFONT_CENTER_Y)
+ fPosY = m_posY + m_height / 2;
+
+ if (IsDisabled())
+ m_textLayout.Render( fPosX, fPosY, m_label.angle, m_label.disabledColor, m_label.shadowColor, m_label.align, m_label.width, true);
+ else if (HasFocus() && m_label.focusedColor)
+ m_textLayout.Render( fPosX, fPosY, m_label.angle, m_label.focusedColor, m_label.shadowColor, m_label.align, m_label.width);
+ else
+ m_textLayout.Render( fPosX, fPosY, m_label.angle, m_label.textColor, m_label.shadowColor, m_label.align, m_label.width);
+
+ // render the second label if it exists
+ CStdString label2(m_info2.GetLabel(m_parentID));
+ if (!label2.IsEmpty())
+ {
+ float textWidth, textHeight;
+ m_textLayout.GetTextExtent(textWidth, textHeight);
+ m_textLayout2.Update(label2);
+
+ float width = m_width - 2 * m_label.offsetX - textWidth - 5;
+ if (width < 0) width = 0;
+ fPosX = m_posX + m_width - m_label.offsetX;
+ uint32_t dwAlign = XBFONT_RIGHT | (m_label.align & XBFONT_CENTER_Y) | XBFONT_TRUNCATED;
+
+ if (IsDisabled() )
+ m_textLayout2.Render( fPosX, fPosY, m_label.angle, m_label.disabledColor, m_label.shadowColor, dwAlign, width, true);
+ else if (HasFocus() && m_label.focusedColor)
+ m_textLayout2.Render( fPosX, fPosY, m_label.angle, m_label.focusedColor, m_label.shadowColor, dwAlign, width);
+ else
+ m_textLayout2.Render( fPosX, fPosY, m_label.angle, m_label.textColor, m_label.shadowColor, dwAlign, width);
+ }
+}
+
+bool CGUIButtonControl::OnAction(const CAction &action)
+{
+ if (action.id == ACTION_SELECT_ITEM)
+ {
+ OnClick();
+ return true;
+ }
+ return CGUIControl::OnAction(action);
+}
+
+bool CGUIButtonControl::OnMessage(CGUIMessage& message)
+{
+ if (message.GetControlId() == GetID())
+ {
+ if (message.GetMessage() == GUI_MSG_LABEL_SET)
+ {
+ SetLabel(message.GetLabel());
+ return true;
+ }
+ if (message.GetMessage() == GUI_MSG_LABEL2_SET)
+ {
+ SetLabel2(message.GetLabel());
+ return true;
+ }
+ if (message.GetMessage() == GUI_MSG_SELECTED)
+ {
+ m_bSelected = true;
+ return true;
+ }
+ if (message.GetMessage() == GUI_MSG_DESELECTED)
+ {
+ m_bSelected = false;
+ return true;
+ }
+ }
+
+ return CGUIControl::OnMessage(message);
+}
+
+void CGUIButtonControl::AllocResources()
+{
+ CGUIControl::AllocResources();
+ m_dwFocusCounter = 0;
+ m_imgFocus.AllocResources();
+ m_imgNoFocus.AllocResources();
+ if (!m_width)
+ m_width = m_imgFocus.GetWidth();
+ if (!m_height)
+ m_height = m_imgFocus.GetHeight();
+}
+
+void CGUIButtonControl::FreeResources()
+{
+ CGUIControl::FreeResources();
+ m_imgFocus.FreeResources();
+ m_imgNoFocus.FreeResources();
+}
+
+void CGUIButtonControl::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+ m_imgFocus.DynamicResourceAlloc(bOnOff);
+ m_imgNoFocus.DynamicResourceAlloc(bOnOff);
+}
+
+void CGUIButtonControl::SetLabel(const string &label)
+{ // NOTE: No fallback for buttons at this point
+ m_info.SetLabel(label, "");
+}
+
+void CGUIButtonControl::SetLabel2(const string &label2)
+{ // NOTE: No fallback for buttons at this point
+ m_info2.SetLabel(label2, "");
+}
+
+void CGUIButtonControl::SetPosition(float posX, float posY)
+{
+ CGUIControl::SetPosition(posX, posY);
+
+ m_imgFocus.SetPosition(posX, posY);
+ m_imgNoFocus.SetPosition(posX, posY);
+}
+
+void CGUIButtonControl::SetAlpha(unsigned char alpha)
+{
+ m_alpha = alpha;
+ m_imgFocus.SetAlpha(alpha);
+ m_imgNoFocus.SetAlpha(alpha);
+}
+
+void CGUIButtonControl::UpdateColors()
+{
+ m_label.UpdateColors();
+ CGUIControl::UpdateColors();
+ m_imgFocus.SetDiffuseColor(m_diffuseColor);
+ m_imgNoFocus.SetDiffuseColor(m_diffuseColor);
+}
+
+bool CGUIButtonControl::OnMouseClick(int button, const CPoint &point)
+{
+ if (button == MOUSE_LEFT_BUTTON)
+ {
+ g_Mouse.SetState(MOUSE_STATE_CLICK);
+ CAction action;
+ action.id = ACTION_SELECT_ITEM;
+ OnAction(action);
+ return true;
+ }
+ return false;
+}
+
+CStdString CGUIButtonControl::GetDescription() const
+{
+ CStdString strLabel(m_info.GetLabel(m_parentID));
+ return strLabel;
+}
+
+CStdString CGUIButtonControl::GetLabel2() const
+{
+ CStdString strLabel(m_info2.GetLabel(m_parentID));
+ return strLabel;
+}
+
+void CGUIButtonControl::PythonSetLabel(const CStdString &strFont, const string &strText, color_t textColor, color_t shadowColor, color_t focusedColor)
+{
+ m_label.font = g_fontManager.GetFont(strFont);
+ m_label.textColor = textColor;
+ m_label.focusedColor = focusedColor;
+ m_label.shadowColor = shadowColor;
+ SetLabel(strText);
+}
+
+void CGUIButtonControl::PythonSetDisabledColor(color_t disabledColor)
+{
+ m_label.disabledColor = disabledColor;
+}
+
+void CGUIButtonControl::RAMSetTextColor(color_t textColor)
+{
+ m_label.textColor = textColor;
+}
+
+void CGUIButtonControl::SettingsCategorySetTextAlign(uint32_t align)
+{
+ m_label.align = align;
+}
+
+void CGUIButtonControl::OnClick()
+{
+ // Save values, as the click message may deactivate the window
+ int controlID = GetID();
+ int parentID = GetParentID();
+ vector<CGUIActionDescriptor> clickActions = m_clickActions;
+
+ // button selected, send a message
+ CGUIMessage msg(GUI_MSG_CLICKED, controlID, parentID, 0);
+ SendWindowMessage(msg);
+
+ // and execute our actions
+ for (unsigned int i = 0; i < clickActions.size(); i++)
+ {
+ CGUIMessage message(GUI_MSG_EXECUTE, controlID, parentID);
+ message.SetAction(clickActions[i]);
+ g_graphicsContext.SendMessage(message);
+ }
+}
+
+void CGUIButtonControl::OnFocus()
+{
+ for (unsigned int i = 0; i < m_focusActions.size(); i++)
+ {
+ CGUIMessage message(GUI_MSG_EXECUTE, m_controlID, m_parentID);
+ message.SetAction(m_focusActions[i]);
+ m_gWindowManager.SendThreadMessage(message);
+ }
+}
+
+void CGUIButtonControl::OnUnFocus()
+{
+ for (unsigned int i = 0; i < m_unfocusActions.size(); i++)
+ {
+ CGUIMessage message(GUI_MSG_EXECUTE, m_controlID, m_parentID);
+ message.SetAction(m_unfocusActions[i]);
+ m_gWindowManager.SendThreadMessage(message);
+ }
+}
+
+void CGUIButtonControl::SetSelected(bool bSelected)
+{
+ if (m_bSelected != bSelected)
+ {
+ m_bSelected = bSelected;
+ SetInvalid();
+ }
+}
+
diff --git a/guilib/GUIButtonControl.h b/guilib/GUIButtonControl.h
new file mode 100644
index 0000000000..8602bd954b
--- /dev/null
+++ b/guilib/GUIButtonControl.h
@@ -0,0 +1,103 @@
+/*!
+\file GUIButtonControl.h
+\brief
+*/
+
+#ifndef GUILIB_GUIBUTTONCONTROL_H
+#define GUILIB_GUIBUTTONCONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUITexture.h"
+#include "GUILabelControl.h" // for CInfoPortion
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIButtonControl : public CGUIControl
+{
+public:
+ CGUIButtonControl(int parentID, int controlID,
+ float posX, float posY, float width, float height,
+ const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus,
+ const CLabelInfo &label);
+
+ virtual ~CGUIButtonControl(void);
+ virtual CGUIButtonControl *Clone() const { return new CGUIButtonControl(*this); };
+
+ virtual void Render();
+ virtual bool OnAction(const CAction &action) ;
+ virtual bool OnMouseClick(int button, const CPoint &point);
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual void SetPosition(float posX, float posY);
+ virtual void SetLabel(const std::string & aLabel);
+ virtual void SetLabel2(const std::string & aLabel2);
+ void SetClickActions(const std::vector<CGUIActionDescriptor>& clickActions) { m_clickActions = clickActions; };
+ const std::vector<CGUIActionDescriptor> &GetClickActions() const { return m_clickActions; };
+ void SetFocusActions(const std::vector<CGUIActionDescriptor>& focusActions) { m_focusActions = focusActions; };
+ void SetUnFocusActions(const std::vector<CGUIActionDescriptor>& unfocusActions) { m_unfocusActions = unfocusActions; };
+ const CLabelInfo& GetLabelInfo() const { return m_label; };
+ virtual CStdString GetLabel() const { return GetDescription(); };
+ virtual CStdString GetLabel2() const;
+ void SetSelected(bool bSelected);
+ virtual CStdString GetDescription() const;
+ void SetAlpha(unsigned char alpha);
+
+ void PythonSetLabel(const CStdString &strFont, const std::string &strText, color_t textColor, color_t shadowColor, color_t focusedColor);
+ void PythonSetDisabledColor(color_t disabledColor);
+
+ void RAMSetTextColor(color_t textColor);
+ void SettingsCategorySetTextAlign(uint32_t align);
+
+ virtual void OnClick();
+ bool HasClickActions() { return m_clickActions.size() > 0; };
+
+ virtual void UpdateColors();
+protected:
+ void OnFocus();
+ void OnUnFocus();
+ virtual void RenderText();
+
+ CGUITexture m_imgFocus;
+ CGUITexture m_imgNoFocus;
+ DWORD m_dwFocusCounter;
+ unsigned char m_alpha;
+
+ CGUIInfoLabel m_info;
+ CGUIInfoLabel m_info2;
+ CLabelInfo m_label;
+ CGUITextLayout m_textLayout;
+ CGUITextLayout m_textLayout2;
+
+ std::vector<CGUIActionDescriptor> m_clickActions;
+ std::vector<CGUIActionDescriptor> m_focusActions;
+ std::vector<CGUIActionDescriptor> m_unfocusActions;
+
+ bool m_bSelected;
+};
+#endif
diff --git a/guilib/GUIButtonScroller.cpp b/guilib/GUIButtonScroller.cpp
new file mode 100644
index 0000000000..1bfc096c5b
--- /dev/null
+++ b/guilib/GUIButtonScroller.cpp
@@ -0,0 +1,951 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIButtonScroller.h"
+#include "GUITextLayout.h"
+#include "LocalizeStrings.h"
+#include "GUIWindowManager.h"
+#include "utils/CharsetConverter.h"
+#include "utils/GUIInfoManager.h"
+#include "SkinInfo.h"
+#include "StringUtils.h"
+#include "GUIControlFactory.h"
+#include "MouseStat.h"
+#include "tinyXML/tinyxml.h"
+#include "Key.h"
+
+using namespace std;
+
+#define SCROLL_SPEED 6.0f
+#define ANALOG_SCROLL_START 0.8f
+
+CGUIButtonScroller::CGUIButtonScroller(int parentID, int controlID, float posX, float posY, float width, float height, float gap, int iSlots, int iDefaultSlot, int iMovementRange, bool bHorizontal, int iAlpha, bool bWrapAround, bool bSmoothScrolling, const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus, const CLabelInfo& labelInfo)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+ , m_imgFocus(posX, posY, width, height, textureFocus)
+ , m_imgNoFocus(posX, posY, width, height, textureNoFocus)
+{
+ m_iXMLNumSlots = iSlots;
+ m_iXMLDefaultSlot = iDefaultSlot - 1;
+ m_xmlPosX = posX;
+ m_xmlPosY = posY;
+ m_xmlWidth = width;
+ m_xmlHeight = height;
+ m_buttonGap = gap;
+ m_iNumSlots = iSlots;
+ m_bHorizontal = bHorizontal;
+ m_iDefaultSlot = iDefaultSlot - 1;
+ m_iMovementRange = iMovementRange;
+ m_iAlpha = iAlpha;
+ m_bWrapAround = bWrapAround;
+ m_bSmoothScrolling = bSmoothScrolling;
+ m_iSlowScrollCount = 0;
+ if (!m_bWrapAround)
+ { // force the amount of movement to allow for the number of slots
+ if (m_iMovementRange < m_iDefaultSlot) m_iMovementRange = m_iDefaultSlot;
+ if (m_iMovementRange < m_iNumSlots - 1 - m_iDefaultSlot) m_iMovementRange = m_iNumSlots - 1 - m_iDefaultSlot;
+ }
+ // reset other variables to the defaults
+ m_iCurrentSlot = -1;
+ m_iOffset = 0;
+ m_scrollOffset = 0;
+ m_bScrollUp = false;
+ m_bScrollDown = false;
+ m_bMoveUp = false;
+ m_bMoveDown = false;
+ m_fAnalogScrollSpeed = 0;
+ ControlType = GUICONTROL_BUTTONBAR;
+ // m_dwFrameCounter = 0;
+ m_label = labelInfo;
+}
+
+CGUIButtonScroller::CGUIButtonScroller(const CGUIButtonScroller &from)
+: CGUIControl(from), m_imgFocus(from.m_imgFocus), m_imgNoFocus(from.m_imgNoFocus)
+{
+ m_iXMLNumSlots = from.m_iXMLNumSlots;
+ m_iXMLDefaultSlot = from.m_iXMLDefaultSlot;
+ m_xmlPosX = from.m_xmlPosX;
+ m_xmlPosY = from.m_xmlPosY;
+ m_xmlWidth = from.m_xmlWidth;
+ m_xmlHeight = from.m_xmlHeight;
+ m_buttonGap = from.m_buttonGap;
+ m_iNumSlots = from.m_iNumSlots;
+ m_bHorizontal = from.m_bHorizontal;
+ m_iDefaultSlot = from.m_iDefaultSlot;
+ m_iMovementRange = from.m_iMovementRange;
+ m_iAlpha = from.m_iAlpha;
+ m_bWrapAround = from.m_bWrapAround;
+ m_bSmoothScrolling = from.m_bSmoothScrolling;
+ m_iSlowScrollCount = 0;
+ // reset other variables to the defaults
+ m_iCurrentSlot = -1;
+ m_iOffset = 0;
+ m_scrollOffset = 0;
+ m_bScrollUp = false;
+ m_bScrollDown = false;
+ m_bMoveUp = false;
+ m_bMoveDown = false;
+ m_fAnalogScrollSpeed = 0;
+ ControlType = GUICONTROL_BUTTONBAR;
+ // m_dwFrameCounter = 0;
+ m_label = from.m_label;
+ // TODO: Clone - copy the buttons across
+
+}
+
+CGUIButtonScroller::~CGUIButtonScroller(void)
+{}
+
+bool CGUIButtonScroller::OnAction(const CAction &action)
+{
+ if (action.id == ACTION_SELECT_ITEM)
+ {
+ // send the appropriate message to the parent window
+ vector<CGUIActionDescriptor> actions = m_vecButtons[GetActiveButton()]->clickActions;
+ for (unsigned int i = 0; i < actions.size(); i++)
+ {
+ CGUIMessage message(GUI_MSG_EXECUTE, GetID(), GetParentID());
+ // find our currently highlighted item
+ message.SetAction(actions[i]);
+ g_graphicsContext.SendMessage(message);
+ }
+ return true;
+ }
+ if (action.id == ACTION_CONTEXT_MENU)
+ { // send a click message to our parent
+ SEND_CLICK_MESSAGE(GetID(), GetParentID(), action.id);
+ return true;
+ }
+ // smooth scrolling (for analog controls)
+ if (action.id == ACTION_SCROLL_UP)
+ {
+ m_fAnalogScrollSpeed += action.amount1 * action.amount1;
+ bool handled = false;
+ while (m_fAnalogScrollSpeed > ANALOG_SCROLL_START)
+ {
+ handled = true;
+ m_fAnalogScrollSpeed -= ANALOG_SCROLL_START;
+ if (!m_bWrapAround && m_iOffset + m_iCurrentSlot == 0)
+ break;
+ DoUp();
+ }
+ return handled;
+ }
+ if (action.id == ACTION_SCROLL_DOWN)
+ {
+ m_fAnalogScrollSpeed += action.amount1 * action.amount1;
+ bool handled = false;
+ while (m_fAnalogScrollSpeed > ANALOG_SCROLL_START)
+ {
+ handled = true;
+ m_fAnalogScrollSpeed -= ANALOG_SCROLL_START;
+ if (!m_bWrapAround && (unsigned int)(m_iOffset + m_iCurrentSlot) == m_vecButtons.size() - 1)
+ break;
+ DoDown();
+ }
+ return handled;
+ }
+ return CGUIControl::OnAction(action);
+}
+
+bool CGUIButtonScroller::OnMessage(CGUIMessage &message)
+{
+ if (message.GetMessage() == GUI_MSG_ITEM_SELECT)
+ {
+ SetActiveButton(message.GetParam1());
+ }
+ else if (message.GetMessage() == GUI_MSG_ITEM_SELECTED)
+ {
+ message.SetParam1(GetActiveButton());
+ return true;
+ }
+ return CGUIControl::OnMessage(message);
+}
+
+void CGUIButtonScroller::ClearButtons()
+{
+ // destroy our buttons (if we have them from a previous viewing)
+ for (int i = 0; i < (int)m_vecButtons.size(); ++i)
+ {
+ CButton* pButton = m_vecButtons[i];
+ delete pButton;
+ }
+ m_vecButtons.erase(m_vecButtons.begin(), m_vecButtons.end());
+}
+
+void CGUIButtonScroller::LoadButtons(TiXmlNode *node)
+{
+ // run through and find all <button> tags
+ // Format is:
+ // <button id="1">
+ // <label>
+ // <execute>
+ // <texturefocus>
+ // <texturenofocus>
+ // </button>
+
+ // TODO: UTF-8 - what if the XML encoding is in UTF-8?
+ TiXmlElement *buttons = node->FirstChildElement("buttons");
+ if (!buttons) return;
+
+ // resolve includes
+ g_SkinInfo.ResolveIncludes(buttons);
+
+ TiXmlElement *buttonNode = buttons->FirstChildElement("button");
+ while (buttonNode)
+ {
+ // resolve includes
+ g_SkinInfo.ResolveIncludes(buttonNode);
+ CButton *button = new CButton;
+ buttonNode->Attribute("id", &button->id);
+ const TiXmlNode *childNode = buttonNode->FirstChild("label");
+ if (childNode && childNode->FirstChild())
+ {
+ CStdString strLabel = childNode->FirstChild()->Value();
+ if (StringUtils::IsNaturalNumber(strLabel))
+ button->strLabel = g_localizeStrings.Get(atoi(strLabel.c_str()));
+ else
+ { // convert to UTF-8
+ CStdString utf8String;
+ g_charsetConverter.unknownToUTF8(strLabel, utf8String);
+ button->strLabel = utf8String;
+ }
+ }
+ // get info
+ childNode = buttonNode->FirstChild("info");
+ if (childNode && childNode->FirstChild())
+ {
+ button->info = g_infoManager.TranslateString(childNode->FirstChild()->Value());
+ }
+ childNode = buttonNode->FirstChild("execute");
+ if (childNode && childNode->FirstChild())
+ {
+ CGUIActionDescriptor action;
+ CGUIControlFactory::GetAction((const TiXmlElement*) childNode, action);
+ button->clickActions.push_back(action);
+ }
+ childNode = buttonNode->FirstChild("onclick");
+ while (childNode && childNode->FirstChild())
+ {
+ CGUIActionDescriptor action;
+ CGUIControlFactory::GetAction((const TiXmlElement*) childNode, action);
+ button->clickActions.push_back(action);
+ childNode = childNode->NextSibling("onclick");
+ }
+ childNode = buttonNode->FirstChild("texturefocus");
+ if (childNode && childNode->FirstChild())
+ button->imageFocus = new CGUITexture(m_posX, m_posY, m_width, m_height, (CStdString)childNode->FirstChild()->Value());
+ childNode = buttonNode->FirstChild("texturenofocus");
+ if (childNode && childNode->FirstChild())
+ button->imageNoFocus = new CGUITexture(m_posX, m_posY, m_width, m_height, (CStdString)childNode->FirstChild()->Value());
+ m_vecButtons.push_back(button);
+ buttonNode = buttonNode->NextSiblingElement("button");
+ }
+}
+
+void CGUIButtonScroller::AllocResources()
+{
+ CGUIControl::AllocResources();
+ // m_dwFrameCounter=0;
+ m_imgFocus.AllocResources();
+ m_imgNoFocus.AllocResources();
+ // calculate our correct width and height
+ if (m_bHorizontal)
+ {
+ m_xmlWidth = (m_iXMLNumSlots * (m_imgFocus.GetWidth() + m_buttonGap) - m_buttonGap);
+ m_xmlHeight = m_imgFocus.GetHeight();
+ }
+ else
+ {
+ m_xmlWidth = m_imgFocus.GetWidth();
+ m_xmlHeight = (m_iXMLNumSlots * (m_imgFocus.GetHeight() + m_buttonGap) - m_buttonGap);
+ }
+ m_width = m_xmlWidth;
+ m_height = m_xmlHeight;
+ // update the number of filled slots etc.
+ if ((int)m_vecButtons.size() < m_iXMLNumSlots)
+ {
+ m_iNumSlots = m_vecButtons.size();
+ m_iDefaultSlot = (int)((float)m_iXMLDefaultSlot / ((float)m_iXMLNumSlots - 1) * ((float)m_iNumSlots - 1));
+ }
+ else
+ {
+ m_iNumSlots = m_iXMLNumSlots;
+ m_iDefaultSlot = m_iXMLDefaultSlot;
+ }
+ SetActiveButton(0);
+}
+
+void CGUIButtonScroller::FreeResources()
+{
+ CGUIControl::FreeResources();
+ m_imgFocus.FreeResources();
+ m_imgNoFocus.FreeResources();
+ ClearButtons();
+}
+
+void CGUIButtonScroller::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+ m_imgFocus.DynamicResourceAlloc(bOnOff);
+ m_imgNoFocus.DynamicResourceAlloc(bOnOff);
+}
+
+void CGUIButtonScroller::Render()
+{
+ if (m_bInvalidated)
+ {
+ if (m_bHorizontal)
+ {
+ m_width = m_iNumSlots * (m_imgFocus.GetWidth() + m_buttonGap) - m_buttonGap;
+ m_height = m_imgFocus.GetHeight();
+ m_posX = m_xmlPosX + (m_xmlWidth - m_width) * 0.5f;
+ m_posY = m_xmlPosY;
+ }
+ else
+ {
+ m_width = m_imgFocus.GetWidth();
+ m_height = m_iNumSlots * (m_imgFocus.GetHeight() + m_buttonGap) - m_buttonGap;
+ m_posX = m_xmlPosX;
+ m_posY = m_xmlPosY + (m_xmlHeight - m_height) * 0.5f;
+ }
+ }
+ float posX = m_posX;
+ float posY = m_posY;
+ // set our viewport
+ g_graphicsContext.SetClipRegion(posX, posY, m_width, m_height);
+ // if we're scrolling, update our scroll offset
+ if (m_bScrollUp || m_bScrollDown)
+ {
+ float maxScroll = m_bHorizontal ? m_imgFocus.GetWidth() : m_imgFocus.GetHeight();
+ maxScroll += m_buttonGap;
+ m_scrollOffset += (int)(maxScroll / m_fScrollSpeed) + 1;
+ if (m_scrollOffset > maxScroll || !m_bSmoothScrolling)
+ {
+ m_scrollOffset = 0;
+ if (m_bScrollUp)
+ {
+ if (GetNext(m_iOffset) != -1) m_iOffset = GetNext(m_iOffset);
+ }
+ else
+ {
+ if (GetPrevious(m_iOffset) != -1) m_iOffset = GetPrevious(m_iOffset);
+ }
+ // check for wraparound...
+ if (!m_bWrapAround)
+ {
+ if (m_iOffset + m_iNumSlots > (int)m_vecButtons.size())
+ m_iOffset = GetPrevious(m_iOffset);
+ }
+ m_bScrollUp = false;
+ m_bScrollDown = false;
+ }
+ else
+ {
+ if (m_bScrollUp)
+ {
+ if (m_bHorizontal)
+ posX -= m_scrollOffset;
+ else
+ posY -= m_scrollOffset;
+ }
+ else
+ {
+ if (m_bHorizontal)
+ posX += m_scrollOffset - maxScroll;
+ else
+ posY += m_scrollOffset - maxScroll;
+ }
+ }
+ }
+ float posX3 = posX;
+ float posY3 = posY;
+ // ok, now check if we're scrolling down
+ int iOffset = m_iOffset;
+ if (m_bScrollDown)
+ {
+ iOffset = GetPrevious(iOffset);
+ RenderItem(posX, posY, iOffset, false);
+ }
+ // ok, now render the main block
+ for (int i = 0; i < m_iNumSlots; i++)
+ RenderItem(posX, posY, iOffset, false);
+ // ok, now check if we're scrolling up
+ if (m_bScrollUp)
+ RenderItem(posX, posY, iOffset, false);
+ // ok, now render the background slot...
+ if (HasFocus())
+ {
+ posX = m_posX;
+ posY = m_posY;
+ // check if we're moving up or down
+ if (m_bMoveUp || m_bMoveDown)
+ {
+ float maxScroll = m_bHorizontal ? m_imgFocus.GetWidth() : m_imgFocus.GetHeight();
+ maxScroll += m_buttonGap;
+ m_scrollOffset += maxScroll / SCROLL_SPEED + 1;
+ if (m_scrollOffset > maxScroll || !m_bSmoothScrolling)
+ {
+ m_scrollOffset = 0;
+ if (m_bMoveUp)
+ {
+ if (m_iCurrentSlot > 0)
+ m_iCurrentSlot--;
+ }
+ else
+ {
+ if (m_iCurrentSlot + 1 < m_iNumSlots)
+ m_iCurrentSlot++;
+ }
+ m_bMoveUp = false;
+ m_bMoveDown = false;
+ }
+ else
+ {
+ if (m_bMoveUp)
+ {
+ if (m_bHorizontal)
+ posX -= m_scrollOffset;
+ else
+ posY -= m_scrollOffset;
+ }
+ else
+ {
+ if (m_bHorizontal)
+ posX += m_scrollOffset;
+ else
+ posY += m_scrollOffset;
+ }
+ }
+ }
+ if (m_bHorizontal)
+ posX += m_iCurrentSlot * ((int)m_imgFocus.GetWidth() + m_buttonGap);
+ else
+ posY += m_iCurrentSlot * ((int)m_imgFocus.GetHeight() + m_buttonGap);
+ // check if we have a skinner-defined icon image
+ CGUITexture *pImage = m_vecButtons[GetActiveButton()]->imageFocus;
+ if (pImage && (m_bScrollUp || m_bScrollDown))
+ pImage = NULL;
+ else if (!pImage)
+ pImage = &m_imgFocus;
+ if (pImage)
+ {
+ pImage->SetPosition(posX, posY);
+ pImage->SetVisible(true);
+ pImage->SetWidth(m_imgFocus.GetWidth());
+ pImage->SetHeight(m_imgFocus.GetHeight());
+ pImage->Render();
+ }
+ }
+ // Now render the text
+ iOffset = m_iOffset;
+ posX = posX3;
+ posY = posY3;
+ if (m_bScrollDown)
+ {
+ iOffset = GetPrevious(iOffset);
+ RenderItem(posX, posY, iOffset, true);
+ }
+ // ok, now render the main block
+ for (int i = 0; i < m_iNumSlots; i++)
+ RenderItem(posX, posY, iOffset, true);
+ // ok, now check if we're scrolling up
+ if (m_bScrollUp)
+ RenderItem(posX, posY, iOffset, true);
+
+ // reset the viewport
+ g_graphicsContext.RestoreClipRegion();
+ CGUIControl::Render();
+}
+
+int CGUIButtonScroller::GetNext(int iCurrent) const
+{
+ if (iCurrent + 1 >= (int)m_vecButtons.size())
+ {
+ if (m_bWrapAround)
+ return 0;
+ else
+ return -1;
+ }
+ else
+ return iCurrent + 1;
+}
+
+int CGUIButtonScroller::GetPrevious(int iCurrent)
+{
+ if (iCurrent - 1 < 0)
+ {
+ if (m_bWrapAround)
+ return m_vecButtons.size() - 1;
+ else
+ return -1;
+ }
+ else
+ return iCurrent -1;
+}
+
+int CGUIButtonScroller::GetButton(int iOffset)
+{
+ return iOffset % ((int)m_vecButtons.size());
+}
+
+void CGUIButtonScroller::SetActiveButton(int iButton)
+{
+ if (iButton >= (int)m_vecButtons.size())
+ iButton = 0;
+ // set the highlighted button
+ m_iCurrentSlot = m_iDefaultSlot;
+ // and the appropriate offset
+ if (!m_bWrapAround)
+ { // check whether there is no wiggle room
+ int iMinButton = m_iDefaultSlot - m_iMovementRange;
+ if (iMinButton < 0) iMinButton = 0;
+ if (iButton < iMinButton)
+ {
+ m_iOffset = 0;
+ m_iCurrentSlot = iMinButton;
+ return ;
+ }
+ int iMaxButton = m_iDefaultSlot + m_iMovementRange;
+ if (iMaxButton >= m_iNumSlots) iMaxButton = m_iNumSlots - 1;
+ if (iButton > iMaxButton)
+ {
+ m_iOffset = iButton - iMaxButton;
+ m_iCurrentSlot = iMaxButton;
+ return ;
+ }
+ // now change our current slot so that it all fits nicely
+ // lastly, make sure we fill the number of slots that we have (if possible)
+ int iNumButtonsToShow = m_vecButtons.size() - iButton + m_iCurrentSlot;
+ if (iNumButtonsToShow < m_iNumSlots && iNumButtonsToShow < (int)m_vecButtons.size())
+ { // we have empty space - try and fill it up
+ while (iNumButtonsToShow < (int)m_vecButtons.size() && m_iCurrentSlot + 1 < m_iNumSlots)
+ {
+ m_iCurrentSlot++;
+ iNumButtonsToShow = m_vecButtons.size() - iButton + m_iCurrentSlot;
+ }
+ }
+ }
+ m_iOffset = 0;
+ for (int i = 0; i < (int)m_vecButtons.size(); i++)
+ {
+ int iItem = i;
+ for (int j = 0; j < m_iCurrentSlot; j++)
+ if (GetNext(iItem) != -1) iItem = GetNext(iItem);
+ if (iItem == iButton)
+ {
+ m_iOffset = i;
+ break;
+ }
+ }
+}
+
+void CGUIButtonScroller::OnUp()
+{
+ if (m_bHorizontal)
+ CGUIControl::OnUp();
+ else if (!m_bWrapAround && m_iOffset + m_iCurrentSlot == 0)
+ {
+ if (m_controlUp != GetID())
+ CGUIControl::OnUp(); // not wrapping around, and we're up the top + our next control is different
+ else
+ SetActiveButton((int)m_vecButtons.size() - 1); // move to the last button in the list
+ }
+ else
+ DoUp();
+}
+
+void CGUIButtonScroller::OnDown()
+{
+ if (m_bHorizontal)
+ CGUIControl::OnDown();
+ else if (!m_bWrapAround && (unsigned int) (m_iOffset + m_iCurrentSlot) == m_vecButtons.size() - 1)
+ {
+ if (m_controlUp != GetID())
+ CGUIControl::OnDown(); // not wrapping around, and we're down the bottom + our next control is different
+ else
+ SetActiveButton(0); // move to the first button in the list
+ }
+ else
+ DoDown();
+}
+
+void CGUIButtonScroller::OnLeft()
+{
+ if (!m_bHorizontal)
+ CGUIControl::OnLeft();
+ else if (!m_bWrapAround && m_iOffset + m_iCurrentSlot == 0 && m_controlLeft != GetID())
+ CGUIControl::OnLeft(); // not wrapping around, and we're at the left + our next control is different
+ else
+ DoUp();
+}
+
+void CGUIButtonScroller::OnRight()
+{
+ if (!m_bHorizontal)
+ CGUIControl::OnRight();
+ else if (!m_bWrapAround && (unsigned int) (m_iOffset + m_iCurrentSlot) == m_vecButtons.size() - 1 && m_controlRight != GetID())
+ CGUIControl::OnRight(); // not wrapping around, and we're at the right + our next control is different
+ else
+ DoDown();
+}
+
+void CGUIButtonScroller::DoUp()
+{
+ if (!m_bScrollUp)
+ {
+ if (m_iCurrentSlot - 1 < m_iDefaultSlot - m_iMovementRange || m_iCurrentSlot - 1 < 0)
+ {
+ if (m_bScrollDown)
+ { // finish scroll for higher speed
+ m_bScrollDown = false;
+ m_scrollOffset = 0;
+ m_iOffset = GetPrevious(m_iOffset);
+ }
+ else
+ {
+ m_bScrollDown = true;
+ m_fScrollSpeed = SCROLL_SPEED;
+ }
+ }
+ else
+ {
+ if (m_bMoveUp)
+ {
+ m_bMoveUp = false;
+ m_scrollOffset = 0;
+ if (m_iCurrentSlot > 0) m_iCurrentSlot--;
+ }
+ m_bMoveUp = true;
+ }
+ }
+}
+
+void CGUIButtonScroller::DoDown()
+{
+ if (!m_bScrollDown)
+ {
+ if (m_iCurrentSlot + 1 > m_iDefaultSlot + m_iMovementRange || m_iCurrentSlot + 1 >= m_iNumSlots)
+ if (m_bScrollUp)
+ { // finish scroll for higher speed
+ m_bScrollUp = false;
+ m_scrollOffset = 0;
+ if (GetNext(m_iOffset) != -1) m_iOffset = GetNext(m_iOffset);
+ }
+ else
+ {
+ m_bScrollUp = true;
+ m_fScrollSpeed = SCROLL_SPEED;
+ }
+ else
+ {
+ if (m_bMoveDown)
+ {
+ m_bMoveDown = false;
+ m_scrollOffset = 0;
+ if (m_iCurrentSlot + 1 < m_iNumSlots) m_iCurrentSlot++;
+ }
+ m_bMoveDown = true;
+ }
+ }
+}
+
+void CGUIButtonScroller::UpdateColors()
+{
+ m_label.UpdateColors();
+ CGUIControl::UpdateColors();
+}
+
+void CGUIButtonScroller::RenderItem(float &posX, float &posY, int &iOffset, bool bText)
+{
+ if (iOffset < 0) return ;
+ float fStartAlpha, fEndAlpha;
+ GetScrollZone(fStartAlpha, fEndAlpha);
+ if (bText)
+ {
+ if (!m_label.font) return ;
+ float fPosX = posX + m_label.offsetX;
+ float fPosY = posY + m_label.offsetY;
+ if (m_label.align & XBFONT_RIGHT)
+ fPosX = posX + m_imgFocus.GetWidth() - m_label.offsetX;
+ if (m_label.align & XBFONT_CENTER_X)
+ fPosX = posX + m_imgFocus.GetWidth() / 2;
+ if (m_label.align & XBFONT_CENTER_Y)
+ fPosY = posY + m_imgFocus.GetHeight() / 2;
+
+ // label is from <info> tag first, and if that's blank,
+ // we use the <label> tag
+ CStdString label = g_infoManager.GetLabel(m_vecButtons[iOffset]->info);
+ if (label.IsEmpty())
+ label = m_vecButtons[iOffset]->strLabel;
+
+ float fAlpha = 255.0f;
+ if (m_bHorizontal)
+ {
+ if (fPosX < fStartAlpha)
+ fAlpha -= (fStartAlpha - fPosX) / (fStartAlpha - m_posX) * m_iAlpha * 2.55f;
+ if (fPosX > fEndAlpha)
+ fAlpha -= (fPosX - fEndAlpha) / (m_posX + m_width - fEndAlpha) * m_iAlpha * 2.55f;
+ }
+ else
+ {
+ if (fPosY < fStartAlpha)
+ fAlpha -= (fStartAlpha - fPosY) / (fStartAlpha - m_posY) * m_iAlpha * 2.55f;
+ if (fPosY > fEndAlpha)
+ fAlpha -= (fPosY - fEndAlpha) / (m_posY + m_height - fEndAlpha) * m_iAlpha * 2.55f;
+ }
+ if (fAlpha < 1) fAlpha = 1; // don't quite go all the way transparent,
+ // as any shadow colour will not be rendered transparent if
+ // it's defined in the font class
+ if (fAlpha > 255) fAlpha = 255.0f;
+ color_t alpha = (color_t)(fAlpha + 0.5f);
+ color_t color = (m_label.focusedColor && iOffset == GetActiveButton()) ? m_label.focusedColor : m_label.textColor;
+ color_t blendedAlpha = (alpha * ((color & 0xff000000) >> 24)) / 255;
+ color_t blendedColor = (blendedAlpha << 24) | (color & 0xFFFFFF);
+ blendedAlpha = (alpha * ((m_label.shadowColor & 0xff000000) >> 24)) / 255;
+ color_t shadowColor = (alpha << 24) | (m_label.shadowColor & 0xFFFFFF);
+ CGUITextLayout::DrawText(m_label.font, fPosX, fPosY, blendedColor, shadowColor, label, m_label.align);
+ }
+ else
+ {
+ float fAlpha = 255.0f;
+ float fAlpha1 = 255.0f;
+ // check if we have a skinner-defined texture...
+ CGUITexture *pImage = m_vecButtons[iOffset]->imageNoFocus;
+ if (!pImage) pImage = &m_imgNoFocus;
+ pImage->SetAlpha(0xFF);
+ pImage->SetVisible(true);
+ if (m_bHorizontal)
+ {
+ if (posX < fStartAlpha)
+ {
+ fAlpha -= (fStartAlpha - posX) / (fStartAlpha - m_posX) * m_iAlpha * 2.55f;
+ fAlpha1 -= (fStartAlpha - (posX + m_imgFocus.GetWidth() + m_buttonGap)) / (fStartAlpha - m_posX) * m_iAlpha * 2.55f;
+ }
+ if (posX >= fEndAlpha)
+ {
+ fAlpha -= (posX - fEndAlpha) / (m_posX + m_width - fEndAlpha) * m_iAlpha * 2.55f;
+ fAlpha1 -= ((posX + m_imgFocus.GetWidth() + m_buttonGap) - fEndAlpha) / (m_posX + m_width - fEndAlpha) * m_iAlpha * 2.55f;
+ }
+ if (fAlpha < 0) fAlpha = 0;
+ if (fAlpha1 < 0) fAlpha1 = 0;
+ if (fAlpha > 255) fAlpha = 255.0f;
+ if (fAlpha1 > 255) fAlpha1 = 255.0f;
+ pImage->SetAlpha((unsigned char)(fAlpha + 0.5f));
+ }
+ else
+ {
+ if (posY < fStartAlpha)
+ {
+ fAlpha -= (fStartAlpha - posY) / (fStartAlpha - m_posY) * m_iAlpha * 2.55f;
+ fAlpha1 -= (fStartAlpha - (posY + m_imgFocus.GetHeight() + m_buttonGap)) / (fStartAlpha - m_posY) * m_iAlpha * 2.55f;
+ }
+ if (posY > fEndAlpha)
+ {
+ fAlpha -= (posY - fEndAlpha) / (m_posY + m_height - fEndAlpha) * m_iAlpha * 2.55f;
+ fAlpha1 -= ((posY + m_imgFocus.GetHeight() + m_buttonGap) - fEndAlpha) / (m_posY + m_height - fEndAlpha) * m_iAlpha * 2.55f;
+ }
+ if (fAlpha < 0) fAlpha = 0;
+ if (fAlpha1 < 0) fAlpha1 = 0;
+ if (fAlpha > 255) fAlpha = 255.0f;
+ if (fAlpha1 > 255) fAlpha1 = 255.0f;
+ pImage->SetAlpha((unsigned char)(fAlpha + 0.5f));
+ }
+ pImage->SetPosition(posX, posY);
+ pImage->SetWidth(m_imgNoFocus.GetWidth());
+ pImage->SetHeight(m_imgNoFocus.GetHeight());
+ pImage->Render();
+ }
+ iOffset = GetNext(iOffset);
+ if (m_bHorizontal)
+ posX += m_imgFocus.GetWidth() + m_buttonGap;
+ else
+ posY += m_imgFocus.GetHeight() + m_buttonGap;
+}
+
+int CGUIButtonScroller::GetActiveButtonID() const
+{
+ int iButton = GetActiveButton();
+ if (iButton < 0 || iButton >= (int)m_vecButtons.size()) return 0;
+ return m_vecButtons[iButton]->id;
+}
+
+int CGUIButtonScroller::GetActiveButton() const
+{
+ if (m_iCurrentSlot < 0) return -1;
+ int iCurrentItem = m_iOffset;
+ for (int i = 0; i < m_iCurrentSlot; i++)
+ if (GetNext(iCurrentItem) != -1) iCurrentItem = GetNext(iCurrentItem);
+ return iCurrentItem;
+}
+
+void CGUIButtonScroller::GetScrollZone(float &fStartAlpha, float &fEndAlpha)
+{
+ // check if we are in the scrollable zone (alpha fade area)
+ // calculate our alpha amount
+ int iMinSlot = m_iDefaultSlot - m_iMovementRange;
+ if (iMinSlot < 0) iMinSlot = 0;
+ int iMaxSlot = m_iDefaultSlot + m_iMovementRange + 1;
+ if (iMaxSlot > m_iNumSlots) iMaxSlot = m_iNumSlots;
+ // calculate the amount of pixels between 0 and iMinSlot
+ if (m_bHorizontal)
+ {
+ fStartAlpha = m_posX + iMinSlot * (m_imgFocus.GetWidth() + m_buttonGap);
+ fEndAlpha = m_posX + iMaxSlot * (m_imgFocus.GetWidth() + m_buttonGap) - m_buttonGap;
+ }
+ else
+ {
+ fStartAlpha = m_posY + iMinSlot * (m_imgFocus.GetHeight() + m_buttonGap);
+ fEndAlpha = m_posY + iMaxSlot * (m_imgFocus.GetHeight() + m_buttonGap) - m_buttonGap;
+ }
+}
+
+bool CGUIButtonScroller::OnMouseOver(const CPoint &point)
+{
+ float fStartAlpha, fEndAlpha;
+ GetScrollZone(fStartAlpha, fEndAlpha);
+ if (m_bHorizontal)
+ {
+ if (point.x < fStartAlpha) // scroll down
+ {
+ m_bScrollUp = false;
+ if (m_iSlowScrollCount > 10) m_iSlowScrollCount = 0;
+ if (m_bSmoothScrolling || m_iSlowScrollCount == 0)
+ m_bScrollDown = true;
+ else
+ m_bScrollDown = false;
+ m_iSlowScrollCount++;
+ m_fScrollSpeed = 50.0f + SCROLL_SPEED - (point.x - fStartAlpha) / (m_posX - fStartAlpha) * 50.0f;
+ }
+ else if (point.x > fEndAlpha - 1) // scroll up
+ {
+ m_bScrollDown = false;
+ if (m_iSlowScrollCount > 10) m_iSlowScrollCount = 0;
+ if (m_bSmoothScrolling || m_iSlowScrollCount == 0)
+ m_bScrollUp = true;
+ else
+ m_bScrollUp = false;
+ m_fScrollSpeed = 50.0f + SCROLL_SPEED - (point.x - fEndAlpha) / (m_posX + m_width - fEndAlpha) * 50.0f;
+ }
+ else // call base class
+ { // select the appropriate item, and call the base class (to set focus)
+ m_iCurrentSlot = (int)((point.x - m_posX) / (m_imgFocus.GetWidth() + m_buttonGap));
+ }
+ }
+ else
+ {
+ if (point.y < fStartAlpha) // scroll down
+ {
+ m_bScrollUp = false;
+ if (m_iSlowScrollCount > 10) m_iSlowScrollCount = 0;
+ if (m_bSmoothScrolling || m_iSlowScrollCount == 0)
+ m_bScrollDown = true;
+ else
+ m_bScrollDown = false;
+ m_iSlowScrollCount++;
+ m_fScrollSpeed = 50.0f + SCROLL_SPEED - (point.y - fStartAlpha) / (m_posY - fStartAlpha) * 50.0f;
+ }
+ else if (point.y > fEndAlpha - 1) // scroll up
+ {
+ m_bScrollDown = false;
+ if (m_iSlowScrollCount > 10) m_iSlowScrollCount = 0;
+ if (m_bSmoothScrolling || m_iSlowScrollCount == 0)
+ m_bScrollUp = true;
+ else
+ m_bScrollUp = false;
+ m_iSlowScrollCount++; m_fScrollSpeed = 50.0f + SCROLL_SPEED - (point.y - fEndAlpha) / (m_posY + m_height - fEndAlpha) * 50.0f;
+ }
+ else
+ { // select the appropriate item, and call the base class (to set focus)
+ m_iCurrentSlot = (int)((point.y - m_posY) / (m_imgFocus.GetHeight() + m_buttonGap));
+ }
+ }
+ return CGUIControl::OnMouseOver(point);
+}
+
+bool CGUIButtonScroller::OnMouseClick(int button, const CPoint &point)
+{
+ if (button != MOUSE_LEFT_BUTTON && button != MOUSE_RIGHT_BUTTON) return false;
+ // check if we are in the clickable button zone
+ float fStartAlpha, fEndAlpha;
+ GetScrollZone(fStartAlpha, fEndAlpha);
+ if (m_bHorizontal)
+ {
+ if (point.x >= fStartAlpha && point.x <= fEndAlpha)
+ { // click the appropriate item
+ m_iCurrentSlot = (int)((point.x - m_posX) / (m_imgFocus.GetWidth() + m_buttonGap));
+ CAction action;
+ if (button == MOUSE_LEFT_BUTTON)
+ action.id = ACTION_SELECT_ITEM;
+ if (button == MOUSE_RIGHT_BUTTON)
+ action.id = ACTION_CONTEXT_MENU;
+ OnAction(action);
+ return true;
+ }
+ }
+ else
+ {
+ if (point.y >= fStartAlpha && point.y <= fEndAlpha)
+ {
+ m_iCurrentSlot = (int)((point.y - m_posY) / (m_imgFocus.GetHeight() + m_buttonGap));
+ CAction action;
+ if (button == MOUSE_LEFT_BUTTON)
+ action.id = ACTION_SELECT_ITEM;
+ if (button == MOUSE_RIGHT_BUTTON)
+ action.id = ACTION_CONTEXT_MENU;
+ OnAction(action);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CGUIButtonScroller::OnMouseWheel(char wheel, const CPoint &point)
+{
+ // check if we are within the clickable button zone
+ float fStartAlpha, fEndAlpha;
+ GetScrollZone(fStartAlpha, fEndAlpha);
+ if ((m_bHorizontal && point.x >= fStartAlpha && point.x <= fEndAlpha) ||
+ (!m_bHorizontal && point.y >= fStartAlpha && point.y <= fEndAlpha))
+ {
+ if (wheel > 0)
+ m_bScrollDown = true;
+ else
+ m_bScrollUp = true;
+ m_fScrollSpeed = SCROLL_SPEED;
+ return true;
+ }
+ return false;
+}
+
+CStdString CGUIButtonScroller::GetDescription() const
+{
+ if (GetActiveButton() >= 0)
+ {
+ CStdString strLabel = m_vecButtons[GetActiveButton()]->strLabel;
+ return strLabel;
+ }
+ return "";
+}
+
+void CGUIButtonScroller::SaveStates(vector<CControlState> &states)
+{
+ states.push_back(CControlState(GetID(), GetActiveButton()));
+}
diff --git a/guilib/GUIButtonScroller.h b/guilib/GUIButtonScroller.h
new file mode 100644
index 0000000000..76d4e5f34a
--- /dev/null
+++ b/guilib/GUIButtonScroller.h
@@ -0,0 +1,128 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+#include "GUITexture.h"
+#include "GUIActionDescriptor.h"
+
+class TiXmlNode;
+
+class CButton
+{
+public:
+ CButton()
+ {
+ id = 0;
+ info = 0;
+ imageFocus = imageNoFocus = NULL;
+ };
+ ~CButton()
+ {
+ delete imageFocus;
+ delete imageNoFocus;
+ }
+ int id;
+ int info;
+ std::string strLabel;
+ std::vector<CGUIActionDescriptor> clickActions;
+ CGUITexture *imageFocus;
+ CGUITexture *imageNoFocus;
+};
+
+class CGUIButtonScroller :
+ public CGUIControl
+{
+public:
+ CGUIButtonScroller(int parentID, int controlID, float posX, float posY, float width, float height, float gap, int iSlots, int iDefaultSlot, int iMovementRange, bool bHorizontal, int iAlpha, bool bWrapAround, bool bSmoothScrolling, const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus, const CLabelInfo& labelInfo);
+ CGUIButtonScroller(const CGUIButtonScroller &from);
+ virtual ~CGUIButtonScroller(void);
+ virtual CGUIButtonScroller *Clone() const { return new CGUIButtonScroller(*this); };
+
+ virtual bool OnAction(const CAction &action);
+ virtual bool OnMessage(CGUIMessage &message);
+ virtual void OnUp();
+ virtual void OnLeft();
+ virtual void OnRight();
+ virtual void OnDown();
+ virtual bool OnMouseOver(const CPoint &point);
+ virtual bool OnMouseClick(int button, const CPoint &point);
+ virtual bool OnMouseWheel(char wheel, const CPoint &point);
+ virtual void Render();
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ void ClearButtons();
+ void AddButton(const std::string &strLabel, const CStdString &strExecute, const int iIcon);
+ void SetActiveButton(int iButton);
+ int GetActiveButton() const;
+ int GetActiveButtonID() const;
+ virtual CStdString GetDescription() const;
+ virtual void SaveStates(std::vector<CControlState> &states);
+ void LoadButtons(TiXmlNode *node);
+
+protected:
+ virtual void UpdateColors();
+ int GetNext(int iCurrent) const;
+ int GetPrevious(int iCurrent);
+ int GetButton(int iOffset);
+ void DoUp();
+ void DoDown();
+ void RenderItem(float &posX, float &posY, int &iOffset, bool bText);
+ void GetScrollZone(float &fStartAlpha, float &fEndAlpha);
+private:
+ // saved variables from the xml (as this control is user editable...)
+ int m_iXMLNumSlots;
+ int m_iXMLDefaultSlot;
+ float m_xmlPosX;
+ float m_xmlPosY;
+ float m_xmlWidth;
+ float m_xmlHeight;
+
+ float m_buttonGap; // gap between buttons
+ int m_iNumSlots; // number of button slots available
+ int m_iDefaultSlot; // default highlight position
+ int m_iMovementRange; // amoung that we can move the highlight
+ bool m_bHorizontal; // true if it's a horizontal button bar
+ int m_iAlpha; // amount of alpha (0..100)
+ bool m_bWrapAround; // whether the buttons wrap around or not
+ bool m_bSmoothScrolling; // whether there is smooth scrolling or not
+
+ int m_iCurrentSlot; // currently highlighted slot
+
+ int m_iOffset; // first item in the list
+ float m_scrollOffset; // offset when scrolling
+ bool m_bScrollUp; // true if we're scrolling up (or left)
+ bool m_bScrollDown; // true if scrolling down (or right)
+ bool m_bMoveUp; // true if we're scrolling up (or left)
+ bool m_bMoveDown; // true if scrolling down (or right)
+ float m_fScrollSpeed; // speed of scrolling
+ float m_fAnalogScrollSpeed; // speed of analog scroll (triggers)
+ // stuff we need for the buttons...
+ std::vector<CButton*> m_vecButtons;
+ typedef std::vector<CButton*>::iterator ivecButtons;
+ CGUITexture m_imgFocus;
+ CGUITexture m_imgNoFocus;
+
+ CLabelInfo m_label;
+ int m_iSlowScrollCount;
+};
diff --git a/guilib/GUICallback.h b/guilib/GUICallback.h
new file mode 100644
index 0000000000..9e2deb5767
--- /dev/null
+++ b/guilib/GUICallback.h
@@ -0,0 +1,193 @@
+#if !defined(GUICALLBACK_H)
+#define GUICALLBACK_H
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "assert.h"
+#include "memory.h"
+
+#ifndef __GNUC__
+#pragma warning( disable : 4786 )
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+// NOTE FROM RUNTiME: An Event holds a weak reference to class method, it acts similar to a //
+// C# delegate method E.g. instantiate an Event and assign it an EventHandler, whenever the //
+// Event is fired the EventHandler is executed. //
+// - There is a 2nd variant of Event called a Callback, this only differs in that a Callback //
+// can return a value after the CallbackHandler has been executed. //
+// - There is a nasty memcpy that gets us over the compiler restriction that prevents us from //
+// casting between two different method pointers, not the cleanest solution granted, but it's //
+// the only way I know how to get around this limitation. //
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+template <class Cookie>
+class GUIEvent
+{
+public:
+
+ typedef void (GUIEvent::*MethodPtr)(Cookie);
+
+ GUIEvent()
+ {
+ m_pInstance = NULL;
+ m_pMethod = NULL;
+ }
+
+ // Assign an EventHandler (EventHandler's are derived from Event)
+ GUIEvent<Cookie> &operator=(GUIEvent<Cookie> &aEvent)
+ {
+ if (&aEvent)
+ {
+ m_pInstance = aEvent.m_pInstance;
+ m_pMethod = aEvent.m_pMethod;
+ }
+ else
+ {
+ GUIEvent();
+ }
+
+ return *this;
+ }
+
+ // Are the class instance and method pointers initialised?
+ bool HasAHandler()
+ {
+ return (m_pInstance && m_pMethod);
+ }
+
+ // Execute the associated class method
+ void Fire(Cookie aCookie)
+ {
+ if (HasAHandler())
+ {
+ (m_pInstance->*m_pMethod)(aCookie);
+ }
+ else
+ {
+ // Event is uninitialized, no handler has been assigned
+ assert(0);
+ }
+ }
+ MethodPtr m_pMethod;
+
+protected:
+ GUIEvent* m_pInstance;
+};
+
+template <class Class, class Cookie>
+class GUIEventHandler : public GUIEvent<Cookie>
+{
+public:
+ typedef void (Class::*MethodPtr)(Cookie);
+
+ GUIEventHandler(Class* pInstance, MethodPtr aMethodPtr)
+ {
+ GUIEvent<Cookie>::m_pInstance = (GUIEvent<Cookie>*) ((LPVOID) pInstance);
+
+#ifndef _LINUX
+ // Its dirty but it works!
+ memcpy(&m_pMethod, &aMethodPtr, sizeof(GUIEvent<Cookie>::m_pMethod));
+#else
+ // Well, GCC doesn't like that dirty stuff... here's another version of the same thing
+ // but even dirtier *grin*
+
+#define my_offsetof(TYPE, MEMBER) \
+ ((size_t)((char *)&(((TYPE *)0x10)->MEMBER) - (char*)0x10))
+
+ void* target = (void*) (((char*) this) + my_offsetof(GUIEvent<Cookie>, m_pMethod));
+ memcpy(target, &aMethodPtr, sizeof(GUIEvent<Cookie>::m_pMethod));
+#endif
+ }
+};
+
+
+// Callbacks are identical to Events except that a Callback returns a result value
+template <class Result, class Cookie>
+class Callback
+{
+public:
+ typedef Result (Callback::*MethodPtr)(Cookie);
+
+ Callback()
+ {
+ m_pInstance = NULL;
+ m_pMethod = NULL;
+ }
+
+ // Assign a CallbackHandler (CallbackHandler's are derived from Callback)
+ Callback<Result, Cookie> &operator=(Callback<Result, Cookie> &aCallback)
+ {
+ if (&aCallback)
+ {
+ m_pInstance = aCallback.m_pInstance;
+ m_pMethod = aCallback.m_pMethod;
+ }
+ else
+ {
+ Callback();
+ }
+
+ return *this;
+ }
+
+ // Are the class instance and method pointers initialised?
+ bool HasAHandler()
+ {
+ return (m_pInstance && m_pMethod);
+ }
+
+ // Execute the associated class method and return the result
+ Result Fire(Cookie aCookie)
+ {
+ if (HasAHandler())
+ {
+ return (m_pInstance->*m_pMethod)(aCookie);
+ }
+
+ // Callback is uninitialized, no handler has been assigned
+ assert(0);
+ return 0;
+ }
+
+protected:
+ Callback* m_pInstance;
+ MethodPtr m_pMethod;
+};
+
+
+template <class Class, class Result, class Cookie>
+class CallbackHandler : public Callback<Result, Cookie>
+{
+public:
+ typedef Result (Class::*MethodPtr)(Cookie);
+
+ CallbackHandler (Class* pInstance, MethodPtr aMethodPtr)
+ {
+ Callback<Result, Cookie>::m_pInstance = (Callback<Result, Cookie>*) ((LPVOID) pInstance);
+ // Its dirty but it works!
+ memcpy(&Callback<Result, Cookie>::m_pMethod, &aMethodPtr, sizeof(Callback<Result, Cookie>::m_pMethod));
+ }
+};
+
+#endif // GUICALLBACK_H
+
diff --git a/guilib/GUICheckMarkControl.cpp b/guilib/GUICheckMarkControl.cpp
new file mode 100644
index 0000000000..4a081576f2
--- /dev/null
+++ b/guilib/GUICheckMarkControl.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUICheckMarkControl.h"
+#include "utils/CharsetConverter.h"
+#include "GUIFontManager.h"
+#include "MouseStat.h"
+#include "Key.h"
+
+using namespace std;
+
+CGUICheckMarkControl::CGUICheckMarkControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& textureCheckMark, const CTextureInfo& textureCheckMarkNF, float checkWidth, float checkHeight, const CLabelInfo &labelInfo)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+ , m_imgCheckMark(posX, posY, checkWidth, checkHeight, textureCheckMark)
+ , m_imgCheckMarkNoFocus(posX, posY, checkWidth, checkHeight, textureCheckMarkNF)
+ , m_textLayout(labelInfo.font, false)
+{
+ m_strLabel = "";
+ m_label = labelInfo;
+ m_bSelected = false;
+ ControlType = GUICONTROL_CHECKMARK;
+}
+
+CGUICheckMarkControl::~CGUICheckMarkControl(void)
+{}
+
+void CGUICheckMarkControl::Render()
+{
+ m_textLayout.Update(m_strLabel);
+
+ float fTextHeight, fTextWidth;
+ m_textLayout.GetTextExtent(fTextWidth, fTextHeight);
+ m_width = fTextWidth + 5 + m_imgCheckMark.GetWidth();
+ m_height = m_imgCheckMark.GetHeight();
+
+ float textPosX = m_posX;
+ float textPosY = m_posY + m_height * 0.5f;
+ float checkMarkPosX = m_posX;
+
+ if (m_label.align & (XBFONT_RIGHT | XBFONT_CENTER_X))
+ textPosX += m_imgCheckMark.GetWidth() + 5;
+ else
+ checkMarkPosX += fTextWidth + 5;
+
+ if (IsDisabled() )
+ m_textLayout.Render(textPosX, textPosY, 0, m_label.disabledColor, m_label.shadowColor, XBFONT_CENTER_Y, 0, true);
+ else if (HasFocus() && m_label.focusedColor)
+ m_textLayout.Render(textPosX, textPosY, 0, m_label.focusedColor, m_label.shadowColor, XBFONT_CENTER_Y, 0);
+ else
+ m_textLayout.Render(textPosX, textPosY, 0, m_label.textColor, m_label.shadowColor, XBFONT_CENTER_Y, 0);
+
+ if (m_bSelected)
+ {
+ m_imgCheckMark.SetPosition(checkMarkPosX, m_posY);
+ m_imgCheckMark.Render();
+ }
+ else
+ {
+ m_imgCheckMarkNoFocus.SetPosition(checkMarkPosX, m_posY);
+ m_imgCheckMarkNoFocus.Render();
+ }
+ CGUIControl::Render();
+}
+
+bool CGUICheckMarkControl::OnAction(const CAction &action)
+{
+ if (action.id == ACTION_SELECT_ITEM)
+ {
+ m_bSelected = !m_bSelected;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID(), action.id);
+ SendWindowMessage(msg);
+ return true;
+ }
+ return CGUIControl::OnAction(action);
+}
+
+bool CGUICheckMarkControl::OnMessage(CGUIMessage& message)
+{
+ if ( message.GetControlId() == GetID() )
+ {
+ if (message.GetMessage() == GUI_MSG_LABEL_SET)
+ {
+ m_strLabel = message.GetLabel();
+ return true;
+ }
+ }
+ if (CGUIControl::OnMessage(message)) return true;
+ return false;
+}
+
+void CGUICheckMarkControl::AllocResources()
+{
+ CGUIControl::AllocResources();
+ m_imgCheckMark.AllocResources();
+ m_imgCheckMarkNoFocus.AllocResources();
+}
+
+void CGUICheckMarkControl::FreeResources()
+{
+ CGUIControl::FreeResources();
+ m_imgCheckMark.FreeResources();
+ m_imgCheckMarkNoFocus.FreeResources();
+}
+
+void CGUICheckMarkControl::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+ m_imgCheckMark.DynamicResourceAlloc(bOnOff);
+ m_imgCheckMarkNoFocus.DynamicResourceAlloc(bOnOff);
+}
+
+void CGUICheckMarkControl::SetSelected(bool bOnOff)
+{
+ m_bSelected = bOnOff;
+}
+
+bool CGUICheckMarkControl::GetSelected() const
+{
+ return m_bSelected;
+}
+
+bool CGUICheckMarkControl::OnMouseClick(int button, const CPoint &point)
+{
+ if (button != MOUSE_LEFT_BUTTON) return false;
+ g_Mouse.SetState(MOUSE_STATE_CLICK);
+ CAction action;
+ action.id = ACTION_SELECT_ITEM;
+ OnAction(action);
+ return true;
+}
+
+void CGUICheckMarkControl::SetLabel(const string &label)
+{
+ m_strLabel = label;
+}
+
+void CGUICheckMarkControl::PythonSetLabel(const CStdString &strFont, const string &strText, color_t textColor)
+{
+ m_label.font = g_fontManager.GetFont(strFont);
+ m_label.textColor = textColor;
+ m_label.focusedColor = textColor;
+ m_strLabel = strText;
+}
+
+void CGUICheckMarkControl::PythonSetDisabledColor(color_t disabledColor)
+{
+ m_label.disabledColor = disabledColor;
+}
+
+void CGUICheckMarkControl::UpdateColors()
+{
+ m_label.UpdateColors();
+ CGUIControl::UpdateColors();
+ m_imgCheckMark.SetDiffuseColor(m_diffuseColor);
+ m_imgCheckMarkNoFocus.SetDiffuseColor(m_diffuseColor);
+}
diff --git a/guilib/GUICheckMarkControl.h b/guilib/GUICheckMarkControl.h
new file mode 100644
index 0000000000..5ff86051d9
--- /dev/null
+++ b/guilib/GUICheckMarkControl.h
@@ -0,0 +1,74 @@
+/*!
+\file GUICheckMarkControl.h
+\brief
+*/
+
+#ifndef CGUILIB_GUICHECKMARK_CONTROL_H
+#define CGUILIB_GUICHECKMARK_CONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUITexture.h"
+#include "GUITextLayout.h"
+#include "GUIControl.h"
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUICheckMarkControl: public CGUIControl
+{
+public:
+ CGUICheckMarkControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& textureCheckMark, const CTextureInfo& textureCheckMarkNF, float checkWidth, float checkHeight, const CLabelInfo &labelInfo);
+ virtual ~CGUICheckMarkControl(void);
+ virtual CGUICheckMarkControl *Clone() const { return new CGUICheckMarkControl(*this); };
+
+ virtual void Render();
+ virtual bool OnAction(const CAction &action) ;
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+
+ void SetLabel(const std::string& strLabel);
+ const std::string GetLabel() const { return m_strLabel; };
+ const CLabelInfo& GetLabelInfo() const { return m_label; };
+ void SetSelected(bool bOnOff);
+ bool GetSelected() const;
+ bool OnMouseClick(int button, const CPoint &point);
+
+ void PythonSetLabel(const CStdString &strFont, const std::string &strText, color_t textColor);
+ void PythonSetDisabledColor(color_t disabledColor);
+
+protected:
+ virtual void UpdateColors();
+ CGUITexture m_imgCheckMark;
+ CGUITexture m_imgCheckMarkNoFocus;
+
+ CLabelInfo m_label;
+ CGUITextLayout m_textLayout;
+ std::string m_strLabel;
+ bool m_bSelected;
+};
+#endif
diff --git a/guilib/GUIColorManager.cpp b/guilib/GUIColorManager.cpp
new file mode 100644
index 0000000000..e8394db8ee
--- /dev/null
+++ b/guilib/GUIColorManager.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIColorManager.h"
+#include "Util.h"
+#include "FileSystem/SpecialProtocol.h"
+#include "SkinInfo.h"
+#include "utils/log.h"
+#include "tinyXML/tinyxml.h"
+
+CGUIColorManager g_colorManager;
+
+CGUIColorManager::CGUIColorManager(void)
+{
+}
+
+CGUIColorManager::~CGUIColorManager(void)
+{
+ Clear();
+}
+
+void CGUIColorManager::Clear()
+{
+ m_colors.clear();
+}
+
+// load the color file in
+void CGUIColorManager::Load(const CStdString &colorFile)
+{
+ Clear();
+
+ // first load the default color map if it exists
+ CStdString path, basePath;
+ CUtil::AddFileToFolder(g_SkinInfo.GetBaseDir(), "colors", basePath);
+ CUtil::AddFileToFolder(basePath, "defaults.xml", path);
+
+ TiXmlDocument xmlDoc;
+ if (xmlDoc.LoadFile(PTH_IC(path)))
+ LoadXML(xmlDoc);
+
+ // now the color map requested
+ if (colorFile.CompareNoCase("SKINDEFAULT") == 0)
+ return; // nothing to do
+
+ CUtil::AddFileToFolder(basePath, colorFile, path);
+ CLog::Log(LOGINFO, "Loading colors from %s", path.c_str());
+
+ if (xmlDoc.LoadFile(path))
+ LoadXML(xmlDoc);
+}
+
+bool CGUIColorManager::LoadXML(TiXmlDocument &xmlDoc)
+{
+ TiXmlElement* pRootElement = xmlDoc.RootElement();
+
+ CStdString strValue = pRootElement->Value();
+ if (strValue != CStdString("colors"))
+ {
+ CLog::Log(LOGERROR, "color file doesnt start with <colors>");
+ return false;
+ }
+
+ const TiXmlElement *color = pRootElement->FirstChildElement("color");
+
+ while (color)
+ {
+ if (color->FirstChild() && color->Attribute("name"))
+ {
+ color_t value = 0xffffffff;
+ sscanf(color->FirstChild()->Value(), "%x", (unsigned int*) &value);
+ CStdString name = color->Attribute("name");
+ iColor it = m_colors.find(name);
+ if (it != m_colors.end())
+ (*it).second = value;
+ else
+ m_colors.insert(make_pair(name, value));
+ }
+ color = color->NextSiblingElement("color");
+ }
+ return true;
+}
+
+// lookup a color and return it's hex value
+color_t CGUIColorManager::GetColor(const CStdString &color) const
+{
+ // look in our color map
+ CStdString trimmed(color);
+ trimmed.TrimLeft("= ");
+ icColor it = m_colors.find(trimmed);
+ if (it != m_colors.end())
+ return (*it).second;
+
+ // try converting hex directly
+ color_t value = 0;
+ sscanf(trimmed.c_str(), "%x", &value);
+ return value;
+}
+
diff --git a/guilib/GUIColorManager.h b/guilib/GUIColorManager.h
new file mode 100644
index 0000000000..e1f66e82c6
--- /dev/null
+++ b/guilib/GUIColorManager.h
@@ -0,0 +1,70 @@
+/*!
+\file GUIColorManager.h
+\brief
+*/
+
+#ifndef GUILIB_COLORMANAGER_H
+#define GUILIB_COLORMANAGER_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+/*!
+ \ingroup textures
+ \brief
+ */
+
+#include "StdString.h"
+
+#include <map>
+
+class TiXmlDocument;
+
+typedef uint32_t color_t;
+
+class CGUIColorManager
+{
+public:
+ CGUIColorManager(void);
+ virtual ~CGUIColorManager(void);
+
+ void Load(const CStdString &colorFile);
+
+ color_t GetColor(const CStdString &color) const;
+
+ void Clear();
+
+protected:
+ bool LoadXML(TiXmlDocument &xmlDoc);
+
+ std::map<CStdString, color_t> m_colors;
+ typedef std::map<CStdString, color_t>::iterator iColor;
+ typedef std::map<CStdString, color_t>::const_iterator icColor;
+};
+
+/*!
+ \ingroup textures
+ \brief
+ */
+extern CGUIColorManager g_colorManager;
+#endif
diff --git a/guilib/GUIControl.cpp b/guilib/GUIControl.cpp
new file mode 100644
index 0000000000..d7ffc3caae
--- /dev/null
+++ b/guilib/GUIControl.cpp
@@ -0,0 +1,887 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+
+#include "utils/GUIInfoManager.h"
+#include "utils/log.h"
+#include "LocalizeStrings.h"
+#include "GUIWindowManager.h"
+#include "GUIControlProfiler.h"
+#include "MouseStat.h"
+#include "Key.h"
+
+using namespace std;
+
+CGUIControl::CGUIControl()
+{
+ m_hasRendered = false;
+ m_bHasFocus = false;
+ m_controlID = 0;
+ m_parentID = 0;
+ m_visible = VISIBLE;
+ m_visibleFromSkinCondition = true;
+ m_forceHidden = false;
+ m_visibleCondition = 0;
+ m_enableCondition = 0;
+ m_enabled = true;
+ m_diffuseColor = 0xffffffff;
+ m_posX = 0;
+ m_posY = 0;
+ m_width = 0;
+ m_height = 0;
+ m_controlLeft = 0;
+ m_controlRight = 0;
+ m_controlUp = 0;
+ m_controlDown = 0;
+ m_controlNext = 0;
+ m_controlPrev = 0;
+ ControlType = GUICONTROL_UNKNOWN;
+ m_bInvalidated = true;
+ m_bAllocated=false;
+ m_parentControl = NULL;
+ m_hasCamera = false;
+ m_pushedUpdates = false;
+ m_pulseOnSelect = false;
+}
+
+CGUIControl::CGUIControl(int parentID, int controlID, float posX, float posY, float width, float height)
+: m_hitRect(posX, posY, posX + width, posY + height)
+{
+ m_posX = posX;
+ m_posY = posY;
+ m_width = width;
+ m_height = height;
+ m_bHasFocus = false;
+ m_controlID = controlID;
+ m_parentID = parentID;
+ m_visible = VISIBLE;
+ m_visibleFromSkinCondition = true;
+ m_diffuseColor = 0xffffffff;
+ m_forceHidden = false;
+ m_visibleCondition = 0;
+ m_enableCondition = 0;
+ m_enabled = true;
+ m_controlLeft = 0;
+ m_controlRight = 0;
+ m_controlUp = 0;
+ m_controlDown = 0;
+ m_controlNext = 0;
+ m_controlPrev = 0;
+ ControlType = GUICONTROL_UNKNOWN;
+ m_bInvalidated = true;
+ m_bAllocated=false;
+ m_hasRendered = false;
+ m_parentControl = NULL;
+ m_hasCamera = false;
+ m_pushedUpdates = false;
+ m_pulseOnSelect = false;
+}
+
+
+CGUIControl::~CGUIControl(void)
+{
+
+}
+
+void CGUIControl::AllocResources()
+{
+ m_hasRendered = false;
+ m_bInvalidated = true;
+ m_bAllocated=true;
+}
+
+void CGUIControl::FreeResources()
+{
+ if (m_bAllocated)
+ {
+ // Reset our animation states - not conditional anims though.
+ // I'm not sure if this is needed for most cases anyway. I believe it's only here
+ // because some windows aren't loaded on demand
+ for (unsigned int i = 0; i < m_animations.size(); i++)
+ {
+ CAnimation &anim = m_animations[i];
+ if (anim.GetType() != ANIM_TYPE_CONDITIONAL)
+ anim.ResetAnimation();
+ }
+ m_bAllocated=false;
+ }
+ m_hasRendered = false;
+}
+
+void CGUIControl::DynamicResourceAlloc(bool bOnOff)
+{
+
+}
+
+// the main render routine.
+// 1. animate and set the animation transform
+// 2. if visible, paint
+// 3. reset the animation transform
+void CGUIControl::DoRender(DWORD currentTime)
+{
+ Animate(currentTime);
+ if (m_hasCamera)
+ g_graphicsContext.SetCameraPosition(m_camera);
+ if (IsVisible())
+ {
+ GUIPROFILER_RENDER_BEGIN(this);
+ Render();
+ GUIPROFILER_RENDER_END(this);
+ }
+ if (m_hasCamera)
+ g_graphicsContext.RestoreCameraPosition();
+ g_graphicsContext.RemoveTransform();
+}
+
+void CGUIControl::Render()
+{
+ m_bInvalidated = false;
+ m_hasRendered = true;
+}
+
+bool CGUIControl::OnAction(const CAction &action)
+{
+ switch (action.id)
+ {
+ case ACTION_MOVE_DOWN:
+ if (!HasFocus()) return false;
+ OnDown();
+ return true;
+ break;
+
+ case ACTION_MOVE_UP:
+ if (!HasFocus()) return false;
+ OnUp();
+ return true;
+ break;
+
+ case ACTION_MOVE_LEFT:
+ if (!HasFocus()) return false;
+ OnLeft();
+ return true;
+ break;
+
+ case ACTION_MOVE_RIGHT:
+ if (!HasFocus()) return false;
+ OnRight();
+ return true;
+ break;
+
+ case ACTION_NEXT_CONTROL:
+ if (!HasFocus()) return false;
+ OnNextControl();
+ return true;
+ break;
+
+ case ACTION_PREV_CONTROL:
+ if (!HasFocus()) return false;
+ OnPrevControl();
+ return true;
+ break;
+ }
+ return false;
+}
+
+// Movement controls (derived classes can override)
+void CGUIControl::OnUp()
+{
+ if (HasFocus())
+ {
+ if (m_upActions.size())
+ ExecuteActions(m_upActions);
+ else if (m_controlID != m_controlUp)
+ {
+ // Send a message to the window with the sender set as the window
+ CGUIMessage msg(GUI_MSG_MOVE, GetParentID(), GetID(), ACTION_MOVE_UP);
+ SendWindowMessage(msg);
+ }
+ }
+}
+
+void CGUIControl::OnDown()
+{
+ if (HasFocus())
+ {
+ if (m_downActions.size())
+ ExecuteActions(m_downActions);
+ else if (m_controlID != m_controlDown)
+ {
+ // Send a message to the window with the sender set as the window
+ CGUIMessage msg(GUI_MSG_MOVE, GetParentID(), GetID(), ACTION_MOVE_DOWN);
+ SendWindowMessage(msg);
+ }
+ }
+}
+
+void CGUIControl::OnLeft()
+{
+ if (HasFocus())
+ {
+ if (m_leftActions.size())
+ ExecuteActions(m_leftActions);
+ else if (m_controlID != m_controlLeft)
+ {
+ // Send a message to the window with the sender set as the window
+ CGUIMessage msg(GUI_MSG_MOVE, GetParentID(), GetID(), ACTION_MOVE_LEFT);
+ SendWindowMessage(msg);
+ }
+ }
+}
+
+void CGUIControl::OnRight()
+{
+ if (HasFocus())
+ {
+ if (m_rightActions.size())
+ ExecuteActions(m_rightActions);
+ else if (m_controlID != m_controlRight)
+ {
+ // Send a message to the window with the sender set as the window
+ CGUIMessage msg(GUI_MSG_MOVE, GetParentID(), GetID(), ACTION_MOVE_RIGHT);
+ SendWindowMessage(msg);
+ }
+ }
+}
+
+void CGUIControl::OnNextControl()
+{
+ if (m_controlID != m_controlNext)
+ {
+ // Send a message to the window with the sender set as the window
+ CGUIMessage msg(GUI_MSG_MOVE, GetParentID(), GetID(), ACTION_NEXT_CONTROL, m_controlNext);
+ SendWindowMessage(msg);
+ }
+}
+
+void CGUIControl::OnPrevControl()
+{
+ if (m_controlID != m_controlPrev)
+ {
+ // Send a message to the window with the sender set as the window
+ CGUIMessage msg(GUI_MSG_MOVE, GetParentID(), GetID(), ACTION_PREV_CONTROL, m_controlPrev);
+ SendWindowMessage(msg);
+ }
+}
+
+bool CGUIControl::SendWindowMessage(CGUIMessage &message)
+{
+ CGUIWindow *pWindow = m_gWindowManager.GetWindow(GetParentID());
+ if (pWindow)
+ return pWindow->OnMessage(message);
+ return g_graphicsContext.SendMessage(message);
+}
+
+int CGUIControl::GetID(void) const
+{
+ return m_controlID;
+}
+
+
+int CGUIControl::GetParentID(void) const
+{
+ return m_parentID;
+}
+
+bool CGUIControl::HasFocus(void) const
+{
+ return m_bHasFocus;
+}
+
+void CGUIControl::SetFocus(bool focus)
+{
+ if (m_bHasFocus && !focus)
+ QueueAnimation(ANIM_TYPE_UNFOCUS);
+ else if (!m_bHasFocus && focus)
+ QueueAnimation(ANIM_TYPE_FOCUS);
+ m_bHasFocus = focus;
+}
+
+bool CGUIControl::OnMessage(CGUIMessage& message)
+{
+ if ( message.GetControlId() == GetID() )
+ {
+ switch (message.GetMessage() )
+ {
+ case GUI_MSG_SETFOCUS:
+ // if control is disabled then move 2 the next control
+ if ( !CanFocus() )
+ {
+ CLog::Log(LOGERROR, "Control %u in window %u has been asked to focus, "
+ "but it can't",
+ GetID(), GetParentID());
+ return false;
+ }
+ SetFocus(true);
+ {
+ // inform our parent window that this has happened
+ CGUIMessage message(GUI_MSG_FOCUSED, GetParentID(), GetID());
+ if (m_parentControl)
+ m_parentControl->OnMessage(message);
+ }
+ return true;
+ break;
+
+ case GUI_MSG_LOSTFOCUS:
+ {
+ SetFocus(false);
+ // and tell our parent so it can unfocus
+ if (m_parentControl)
+ m_parentControl->OnMessage(message);
+ return true;
+ }
+ break;
+
+ case GUI_MSG_VISIBLE:
+ if (m_visibleCondition)
+ m_visible = g_infoManager.GetBool(m_visibleCondition, m_parentID) ? VISIBLE : HIDDEN;
+ else
+ m_visible = VISIBLE;
+ m_forceHidden = false;
+ return true;
+ break;
+
+ case GUI_MSG_HIDDEN:
+ m_forceHidden = true;
+ // reset any visible animations that are in process
+ if (IsAnimating(ANIM_TYPE_VISIBLE))
+ {
+// CLog::DebugLog("Resetting visible animation on control %i (we are %s)", m_controlID, m_visible ? "visible" : "hidden");
+ CAnimation *visibleAnim = GetAnimation(ANIM_TYPE_VISIBLE);
+ if (visibleAnim) visibleAnim->ResetAnimation();
+ }
+ return true;
+
+ // Note that the skin <enable> tag will override these messages
+ case GUI_MSG_ENABLED:
+ SetEnabled(true);
+ return true;
+
+ case GUI_MSG_DISABLED:
+ SetEnabled(false);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CGUIControl::CanFocus() const
+{
+ if (!IsVisible() && !m_allowHiddenFocus) return false;
+ if (IsDisabled()) return false;
+ return true;
+}
+
+bool CGUIControl::IsVisible() const
+{
+ if (m_forceHidden) return false;
+ return m_visible == VISIBLE;
+}
+
+bool CGUIControl::IsDisabled() const
+{
+ return !m_enabled;
+}
+
+void CGUIControl::SetEnabled(bool bEnable)
+{
+ m_enabled = bEnable;
+}
+
+void CGUIControl::SetEnableCondition(int condition)
+{
+ m_enableCondition = condition;
+}
+
+void CGUIControl::SetPosition(float posX, float posY)
+{
+ if ((m_posX != posX) || (m_posY != posY))
+ {
+ m_hitRect += CPoint(posX - m_posX, posY - m_posY);
+ m_posX = posX;
+ m_posY = posY;
+ SetInvalid();
+ }
+}
+
+void CGUIControl::SetColorDiffuse(const CGUIInfoColor &color)
+{
+ m_diffuseColor = color;
+}
+
+float CGUIControl::GetXPosition() const
+{
+ return m_posX;
+}
+
+float CGUIControl::GetYPosition() const
+{
+ return m_posY;
+}
+
+float CGUIControl::GetWidth() const
+{
+ return m_width;
+}
+
+float CGUIControl::GetHeight() const
+{
+ return m_height;
+}
+
+void CGUIControl::SetNavigation(int up, int down, int left, int right)
+{
+ m_controlUp = up;
+ m_controlDown = down;
+ m_controlLeft = left;
+ m_controlRight = right;
+}
+
+void CGUIControl::SetTabNavigation(int next, int prev)
+{
+ m_controlNext = next;
+ m_controlPrev = prev;
+}
+
+void CGUIControl::SetNavigationActions(const vector<CGUIActionDescriptor> &up, const vector<CGUIActionDescriptor> &down,
+ const vector<CGUIActionDescriptor> &left, const vector<CGUIActionDescriptor> &right)
+{
+ m_leftActions = left;
+ m_rightActions = right;
+ m_upActions = up;
+ m_downActions = down;
+}
+
+void CGUIControl::SetWidth(float width)
+{
+ if (m_width != width)
+ {
+ m_width = width;
+ m_hitRect.x2 = m_hitRect.x1 + width;
+ SetInvalid();
+ }
+}
+
+void CGUIControl::SetHeight(float height)
+{
+ if (m_height != height)
+ {
+ m_height = height;
+ m_hitRect.y2 = m_hitRect.y1 + height;
+ SetInvalid();
+ }
+}
+
+void CGUIControl::SetVisible(bool bVisible)
+{
+ // just force to hidden if necessary
+ m_forceHidden = !bVisible;
+/*
+ if (m_visibleCondition)
+ bVisible = g_infoManager.GetBool(m_visibleCondition, m_parentID);
+ if (m_bVisible != bVisible)
+ {
+ m_visible = bVisible;
+ m_visibleFromSkinCondition = bVisible;
+ SetInvalid();
+ }*/
+}
+
+bool CGUIControl::HitTest(const CPoint &point) const
+{
+ return m_hitRect.PtInRect(point);
+}
+
+// override this function to implement custom mouse behaviour
+bool CGUIControl::OnMouseOver(const CPoint &point)
+{
+ if (g_Mouse.GetState() != MOUSE_STATE_DRAG)
+ g_Mouse.SetState(MOUSE_STATE_FOCUS);
+ if (!CanFocus()) return false;
+ CGUIMessage msg(GUI_MSG_SETFOCUS, GetParentID(), GetID());
+ OnMessage(msg);
+ return true;
+}
+
+void CGUIControl::UpdateVisibility(const CGUIListItem *item)
+{
+ if (m_visibleCondition)
+ {
+ bool bWasVisible = m_visibleFromSkinCondition;
+ m_visibleFromSkinCondition = g_infoManager.GetBool(m_visibleCondition, m_parentID, item);
+ if (!bWasVisible && m_visibleFromSkinCondition)
+ { // automatic change of visibility - queue the in effect
+ // CLog::DebugLog("Visibility changed to visible for control id %i", m_controlID);
+ QueueAnimation(ANIM_TYPE_VISIBLE);
+ }
+ else if (bWasVisible && !m_visibleFromSkinCondition)
+ { // automatic change of visibility - do the out effect
+ // CLog::DebugLog("Visibility changed to hidden for control id %i", m_controlID);
+ QueueAnimation(ANIM_TYPE_HIDDEN);
+ }
+ }
+ // check for conditional animations
+ for (unsigned int i = 0; i < m_animations.size(); i++)
+ {
+ CAnimation &anim = m_animations[i];
+ if (anim.GetType() == ANIM_TYPE_CONDITIONAL)
+ anim.UpdateCondition(GetParentID(), item);
+ }
+ // and check for conditional enabling - note this overrides SetEnabled() from the code currently
+ // this may need to be reviewed at a later date
+ if (m_enableCondition)
+ m_enabled = g_infoManager.GetBool(m_enableCondition, m_parentID, item);
+ m_allowHiddenFocus.Update(m_parentID, item);
+ UpdateColors();
+ // and finally, update our control information (if not pushed)
+ if (!m_pushedUpdates)
+ UpdateInfo(item);
+}
+
+void CGUIControl::UpdateColors()
+{
+ m_diffuseColor.Update();
+}
+
+void CGUIControl::SetInitialVisibility()
+{
+ if (m_visibleCondition)
+ {
+ m_visibleFromSkinCondition = g_infoManager.GetBool(m_visibleCondition, m_parentID);
+ m_visible = m_visibleFromSkinCondition ? VISIBLE : HIDDEN;
+ // CLog::DebugLog("Set initial visibility for control %i: %s", m_controlID, m_visible == VISIBLE ? "visible" : "hidden");
+ // no need to enquire every frame if we are always visible or always hidden
+ if (m_visibleCondition == SYSTEM_ALWAYS_TRUE || m_visibleCondition == SYSTEM_ALWAYS_FALSE)
+ m_visibleCondition = 0;
+ }
+ // and handle animation conditions as well
+ for (unsigned int i = 0; i < m_animations.size(); i++)
+ {
+ CAnimation &anim = m_animations[i];
+ if (anim.GetType() == ANIM_TYPE_CONDITIONAL)
+ anim.SetInitialCondition(GetParentID());
+ }
+ m_allowHiddenFocus.Update(m_parentID);
+ UpdateColors();
+}
+
+void CGUIControl::SetVisibleCondition(int visible, const CGUIInfoBool &allowHiddenFocus)
+{
+ m_visibleCondition = visible;
+ m_allowHiddenFocus = allowHiddenFocus;
+}
+
+void CGUIControl::SetAnimations(const vector<CAnimation> &animations)
+{
+ m_animations = animations;
+}
+
+void CGUIControl::ResetAnimation(ANIMATION_TYPE type)
+{
+ for (unsigned int i = 0; i < m_animations.size(); i++)
+ {
+ if (m_animations[i].GetType() == type)
+ m_animations[i].ResetAnimation();
+ }
+}
+
+void CGUIControl::ResetAnimations()
+{
+ for (unsigned int i = 0; i < m_animations.size(); i++)
+ m_animations[i].ResetAnimation();
+}
+
+bool CGUIControl::CheckAnimation(ANIMATION_TYPE animType)
+{
+ // rule out the animations we shouldn't perform
+ if (!IsVisible() || !HasRendered())
+ { // hidden or never rendered - don't allow exit or entry animations for this control
+ if (animType == ANIM_TYPE_WINDOW_CLOSE)
+ { // could be animating a (delayed) window open anim, so reset it
+ ResetAnimation(ANIM_TYPE_WINDOW_OPEN);
+ return false;
+ }
+ }
+ if (!IsVisible())
+ { // hidden - only allow hidden anims if we're animating a visible anim
+ if (animType == ANIM_TYPE_HIDDEN && !IsAnimating(ANIM_TYPE_VISIBLE))
+ {
+ // update states to force it hidden
+ UpdateStates(animType, ANIM_PROCESS_NORMAL, ANIM_STATE_APPLIED);
+ return false;
+ }
+ if (animType == ANIM_TYPE_WINDOW_OPEN)
+ return false;
+ }
+ return true;
+}
+
+void CGUIControl::QueueAnimation(ANIMATION_TYPE animType)
+{
+ if (!CheckAnimation(animType))
+ return;
+ CAnimation *reverseAnim = GetAnimation((ANIMATION_TYPE)-animType, false);
+ CAnimation *forwardAnim = GetAnimation(animType);
+ // we first check whether the reverse animation is in progress (and reverse it)
+ // then we check for the normal animation, and queue it
+ if (reverseAnim && reverseAnim->IsReversible() && (reverseAnim->GetState() == ANIM_STATE_IN_PROCESS || reverseAnim->GetState() == ANIM_STATE_DELAYED))
+ {
+ reverseAnim->QueueAnimation(ANIM_PROCESS_REVERSE);
+ if (forwardAnim) forwardAnim->ResetAnimation();
+ }
+ else if (forwardAnim)
+ {
+ forwardAnim->QueueAnimation(ANIM_PROCESS_NORMAL);
+ if (reverseAnim) reverseAnim->ResetAnimation();
+ }
+ else
+ { // hidden and visible animations delay the change of state. If there is no animations
+ // to perform, then we should just change the state straightaway
+ if (reverseAnim) reverseAnim->ResetAnimation();
+ UpdateStates(animType, ANIM_PROCESS_NORMAL, ANIM_STATE_APPLIED);
+ }
+}
+
+CAnimation *CGUIControl::GetAnimation(ANIMATION_TYPE type, bool checkConditions /* = true */)
+{
+ for (unsigned int i = 0; i < m_animations.size(); i++)
+ {
+ CAnimation &anim = m_animations[i];
+ if (anim.GetType() == type)
+ {
+ if (!checkConditions || !anim.GetCondition() || g_infoManager.GetBool(anim.GetCondition()))
+ return &anim;
+ }
+ }
+ return NULL;
+}
+
+bool CGUIControl::HasAnimation(ANIMATION_TYPE type)
+{
+ return (NULL != GetAnimation(type, true));
+}
+
+void CGUIControl::UpdateStates(ANIMATION_TYPE type, ANIMATION_PROCESS currentProcess, ANIMATION_STATE currentState)
+{
+ // Make sure control is hidden or visible at the appropriate times
+ // while processing a visible or hidden animation it needs to be visible,
+ // but when finished a hidden operation it needs to be hidden
+ if (type == ANIM_TYPE_VISIBLE)
+ {
+ if (currentProcess == ANIM_PROCESS_REVERSE)
+ {
+ if (currentState == ANIM_STATE_APPLIED)
+ m_visible = HIDDEN;
+ }
+ else if (currentProcess == ANIM_PROCESS_NORMAL)
+ {
+ if (currentState == ANIM_STATE_DELAYED)
+ m_visible = DELAYED;
+ else
+ m_visible = m_visibleFromSkinCondition ? VISIBLE : HIDDEN;
+ }
+ }
+ else if (type == ANIM_TYPE_HIDDEN)
+ {
+ if (currentProcess == ANIM_PROCESS_NORMAL) // a hide animation
+ {
+ if (currentState == ANIM_STATE_APPLIED)
+ m_visible = HIDDEN; // finished
+ else
+ m_visible = VISIBLE; // have to be visible until we are finished
+ }
+ else if (currentProcess == ANIM_PROCESS_REVERSE) // a visible animation
+ { // no delay involved here - just make sure it's visible
+ m_visible = m_visibleFromSkinCondition ? VISIBLE : HIDDEN;
+ }
+ }
+ else if (type == ANIM_TYPE_WINDOW_OPEN)
+ {
+ if (currentProcess == ANIM_PROCESS_NORMAL)
+ {
+ if (currentState == ANIM_STATE_DELAYED)
+ m_visible = DELAYED; // delayed
+ else
+ m_visible = m_visibleFromSkinCondition ? VISIBLE : HIDDEN;
+ }
+ }
+ else if (type == ANIM_TYPE_FOCUS)
+ {
+ // call the focus function if we have finished a focus animation
+ // (buttons can "click" on focus)
+ if (currentProcess == ANIM_PROCESS_NORMAL && currentState == ANIM_STATE_APPLIED)
+ OnFocus();
+ }
+ else if (type == ANIM_TYPE_UNFOCUS)
+ {
+ // call the unfocus function if we have finished a focus animation
+ // (buttons can "click" on focus)
+ if (currentProcess == ANIM_PROCESS_NORMAL && currentState == ANIM_STATE_APPLIED)
+ OnUnFocus();
+ }
+}
+
+void CGUIControl::Animate(DWORD currentTime)
+{
+ // check visible state outside the loop, as it could change
+ GUIVISIBLE visible = m_visible;
+ m_transform.Reset();
+ CPoint center(m_posX + m_width * 0.5f, m_posY + m_height * 0.5f);
+ for (unsigned int i = 0; i < m_animations.size(); i++)
+ {
+ CAnimation &anim = m_animations[i];
+ anim.Animate(currentTime, HasRendered() || visible == DELAYED);
+ // Update the control states (such as visibility)
+ UpdateStates(anim.GetType(), anim.GetProcess(), anim.GetState());
+ // and render the animation effect
+ anim.RenderAnimation(m_transform, center);
+
+/* // debug stuff
+ if (anim.currentProcess != ANIM_PROCESS_NONE)
+ {
+ if (anim.effect == EFFECT_TYPE_ZOOM)
+ {
+ if (IsVisible())
+ CLog::DebugLog("Animating control %d with a %s zoom effect %s. Amount is %2.1f, visible=%s", m_controlID, anim.type == ANIM_TYPE_CONDITIONAL ? (anim.lastCondition ? "conditional_on" : "conditional_off") : (anim.type == ANIM_TYPE_VISIBLE ? "visible" : "hidden"), anim.currentProcess == ANIM_PROCESS_NORMAL ? "normal" : "reverse", anim.amount, IsVisible() ? "true" : "false");
+ }
+ else if (anim.effect == EFFECT_TYPE_FADE)
+ {
+ if (IsVisible())
+ CLog::DebugLog("Animating control %d with a %s fade effect %s. Amount is %2.1f. Visible=%s", m_controlID, anim.type == ANIM_TYPE_CONDITIONAL ? (anim.lastCondition ? "conditional_on" : "conditional_off") : (anim.type == ANIM_TYPE_VISIBLE ? "visible" : "hidden"), anim.currentProcess == ANIM_PROCESS_NORMAL ? "normal" : "reverse", anim.amount, IsVisible() ? "true" : "false");
+ }
+ }*/
+ }
+ g_graphicsContext.AddTransform(m_transform);
+}
+
+bool CGUIControl::IsAnimating(ANIMATION_TYPE animType)
+{
+ for (unsigned int i = 0; i < m_animations.size(); i++)
+ {
+ CAnimation &anim = m_animations[i];
+ if (anim.GetType() == animType)
+ {
+ if (anim.GetQueuedProcess() == ANIM_PROCESS_NORMAL)
+ return true;
+ if (anim.GetProcess() == ANIM_PROCESS_NORMAL)
+ return true;
+ }
+ else if (anim.GetType() == -animType)
+ {
+ if (anim.GetQueuedProcess() == ANIM_PROCESS_REVERSE)
+ return true;
+ if (anim.GetProcess() == ANIM_PROCESS_REVERSE)
+ return true;
+ }
+ }
+ return false;
+}
+
+int CGUIControl::GetNextControl(int direction) const
+{
+ switch (direction)
+ {
+ case ACTION_MOVE_UP:
+ return m_controlUp;
+ case ACTION_MOVE_DOWN:
+ return m_controlDown;
+ case ACTION_MOVE_LEFT:
+ return m_controlLeft;
+ case ACTION_MOVE_RIGHT:
+ return m_controlRight;
+ default:
+ return -1;
+ }
+}
+
+// input the point with respect to this control to hit, and return
+// the control and the point with respect to his control if we have a hit
+bool CGUIControl::CanFocusFromPoint(const CPoint &point, CGUIControl **control, CPoint &controlPoint) const
+{
+ controlPoint = point;
+ m_transform.InverseTransformPosition(controlPoint.x, controlPoint.y);
+ if (CanFocus() && HitTest(controlPoint))
+ {
+ *control = (CGUIControl *)this;
+ return true;
+ }
+ *control = NULL;
+ return false;
+}
+
+void CGUIControl::UnfocusFromPoint(const CPoint &point)
+{
+ CPoint controlPoint(point);
+ m_transform.InverseTransformPosition(controlPoint.x, controlPoint.y);
+ if (!HitTest(controlPoint))
+ SetFocus(false);
+}
+
+bool CGUIControl::HasID(int id) const
+{
+ return GetID() == id;
+}
+
+bool CGUIControl::HasVisibleID(int id) const
+{
+ return GetID() == id && IsVisible();
+}
+
+void CGUIControl::SaveStates(vector<CControlState> &states)
+{
+ // empty for now - do nothing with the majority of controls
+}
+
+void CGUIControl::SetHitRect(const CRect &rect)
+{
+ m_hitRect = rect;
+}
+
+void CGUIControl::SetCamera(const CPoint &camera)
+{
+ m_camera = camera;
+ m_hasCamera = true;
+}
+
+void CGUIControl::ExecuteActions(const vector<CGUIActionDescriptor> &actions)
+{
+ // we should really save anything we need, as the action may cause the window to close
+ int savedID = GetID();
+ int savedParent = GetParentID();
+ vector<CGUIActionDescriptor> savedActions = actions;
+
+ for (unsigned int i = 0; i < savedActions.size(); i++)
+ {
+ CGUIMessage message(GUI_MSG_EXECUTE, savedID, savedParent);
+ message.SetAction(savedActions[i]);
+ g_graphicsContext.SendMessage(message);
+ }
+}
+
+CPoint CGUIControl::GetRenderPosition() const
+{
+ float z = 0;
+ CPoint point(m_posX, m_posY);
+ m_transform.TransformPosition(point.x, point.y, z);
+ if (m_parentControl)
+ point += m_parentControl->GetRenderPosition();
+ return point;
+}
diff --git a/guilib/GUIControl.h b/guilib/GUIControl.h
new file mode 100644
index 0000000000..4de51176c3
--- /dev/null
+++ b/guilib/GUIControl.h
@@ -0,0 +1,317 @@
+/*!
+\file GUIControl.h
+\brief
+*/
+
+#ifndef GUILIB_GUICONTROL_H
+#define GUILIB_GUICONTROL_H
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GraphicContext.h" // needed by any rendering operation (all controls)
+#include "GUIMessage.h" // needed by practically all controls
+#include "GUIFont.h" // needed for the CAngle member (CLabelInfo) among other stuff
+#include "VisibleEffect.h" // needed for the CAnimation members
+#include "GUIInfoColor.h" // needed for CGuiInfoColor to handle infolabel'ed colors
+#include "GUIActionDescriptor.h"
+
+class CGUIListItem; // forward
+class CAction;
+
+enum ORIENTATION { HORIZONTAL = 0, VERTICAL };
+
+class CLabelInfo
+{
+public:
+ CLabelInfo()
+ {
+ font = NULL;
+ align = XBFONT_LEFT;
+ offsetX = offsetY = 0;
+ width = 0;
+ angle = 0;
+ };
+ void UpdateColors()
+ {
+ textColor.Update();
+ shadowColor.Update();
+ selectedColor.Update();
+ disabledColor.Update();
+ focusedColor.Update();
+ };
+
+ CGUIInfoColor textColor;
+ CGUIInfoColor shadowColor;
+ CGUIInfoColor selectedColor;
+ CGUIInfoColor disabledColor;
+ CGUIInfoColor focusedColor;
+ uint32_t align;
+ float offsetX;
+ float offsetY;
+ float width;
+ float angle;
+ CGUIFont *font;
+};
+
+class CControlState
+{
+public:
+ CControlState(int id, int data)
+ {
+ m_id = id;
+ m_data = data;
+ }
+ int m_id;
+ int m_data;
+};
+
+/*!
+ \ingroup controls
+ \brief Base class for controls
+ */
+class CGUIControl
+{
+public:
+ CGUIControl();
+ CGUIControl(int parentID, int controlID, float posX, float posY, float width, float height);
+ virtual ~CGUIControl(void);
+ virtual CGUIControl *Clone() const=0;
+
+ virtual void DoRender(DWORD currentTime);
+ virtual void Render();
+ bool HasRendered() const { return m_hasRendered; };
+
+ // OnAction() is called by our window when we are the focused control.
+ // We should process any control-specific actions in the derived classes,
+ // and return true if we have taken care of the action. Returning false
+ // indicates that the message may be handed down to the window or application
+ // levels. This base class implementation handles basic movement, and should
+ // be called from the derived classes when the action has not been handled.
+ // Return true to indicate that the action has been dealt with.
+ virtual bool OnAction(const CAction &action);
+
+ // Common actions to make the code easier to read (no ugly switch statements in derived controls)
+ virtual void OnUp();
+ virtual void OnDown();
+ virtual void OnLeft();
+ virtual void OnRight();
+ virtual void OnNextControl();
+ virtual void OnPrevControl();
+ virtual void OnFocus() {};
+ virtual void OnUnFocus() {};
+
+ /// \brief Called when the mouse is over the control. Default implementation selects the control.
+ virtual bool OnMouseOver(const CPoint &point);
+ /// \brief Called when the mouse is dragging over the control. Default implementation does nothing.
+ virtual bool OnMouseDrag(const CPoint &offset, const CPoint &point) { return false; };
+ /// \brief Called when the left mouse button is pressed on the control. Default implementation does nothing.
+ virtual bool OnMouseClick(int button, const CPoint &point) { return false; };
+ /// \brief Called when the left mouse button is pressed on the control. Default implementation does nothing.
+ virtual bool OnMouseDoubleClick(int button, const CPoint &point) { return false; };
+ /// \brief Called when the mouse wheel has moved whilst over the control. Default implementation does nothing
+ virtual bool OnMouseWheel(char wheel, const CPoint &point) { return false; };
+ /// \brief Used to test whether the pointer location (fPosX, fPosY) is inside the control. For mouse events.
+ virtual bool HitTest(const CPoint &point) const;
+ /// \brief Focus a control from a screen location. Returns the coordinates of the screen location relative to the control and a pointer to the control.
+ virtual bool CanFocusFromPoint(const CPoint &point, CGUIControl **control, CPoint &controlPoint) const;
+ /// \brief Unfocus a control if it's not in a screen location.
+ virtual void UnfocusFromPoint(const CPoint &point);
+
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual int GetID(void) const;
+ void SetID(int id) { m_controlID = id; };
+ virtual bool HasID(int id) const;
+ virtual bool HasVisibleID(int id) const;
+ int GetParentID() const;
+ virtual bool HasFocus() const;
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual bool IsDynamicallyAllocated() { return false; };
+ virtual bool CanFocus() const;
+ virtual bool IsVisible() const;
+ bool IsVisibleFromSkin() const { return m_visibleFromSkinCondition; };
+ virtual bool IsDisabled() const;
+ virtual void SetPosition(float posX, float posY);
+ virtual void SetHitRect(const CRect &rect);
+ virtual void SetCamera(const CPoint &camera);
+ void SetColorDiffuse(const CGUIInfoColor &color);
+ CPoint GetRenderPosition() const;
+ virtual float GetXPosition() const;
+ virtual float GetYPosition() const;
+ virtual float GetWidth() const;
+ virtual float GetHeight() const;
+ virtual void SetNavigation(int up, int down, int left, int right);
+ virtual void SetTabNavigation(int next, int prev);
+ virtual void SetNavigationActions(const std::vector<CGUIActionDescriptor> &up, const std::vector<CGUIActionDescriptor> &down,
+ const std::vector<CGUIActionDescriptor> &left, const std::vector<CGUIActionDescriptor> &right);
+ void ExecuteActions(const std::vector<CGUIActionDescriptor> &actions);
+ int GetControlIdUp() const { return m_controlUp;};
+ int GetControlIdDown() const { return m_controlDown;};
+ int GetControlIdLeft() const { return m_controlLeft;};
+ int GetControlIdRight() const { return m_controlRight;};
+ virtual int GetNextControl(int direction) const;
+ virtual void SetFocus(bool focus);
+ virtual void SetWidth(float width);
+ virtual void SetHeight(float height);
+ virtual void SetVisible(bool bVisible);
+ void SetVisibleCondition(int visible, const CGUIInfoBool &allowHiddenFocus);
+ int GetVisibleCondition() const { return m_visibleCondition; };
+ void SetEnableCondition(int condition);
+ virtual void UpdateVisibility(const CGUIListItem *item = NULL);
+ virtual void SetInitialVisibility();
+ virtual void SetEnabled(bool bEnable);
+ virtual void SetInvalid() { m_bInvalidated = true; };
+ virtual void SetPulseOnSelect(bool pulse) { m_pulseOnSelect = pulse; };
+ virtual CStdString GetDescription() const { return ""; };
+
+ void SetAnimations(const std::vector<CAnimation> &animations);
+ const std::vector<CAnimation> &GetAnimations() const { return m_animations; };
+
+ virtual void QueueAnimation(ANIMATION_TYPE anim);
+ virtual bool IsAnimating(ANIMATION_TYPE anim);
+ virtual bool HasAnimation(ANIMATION_TYPE anim);
+ CAnimation *GetAnimation(ANIMATION_TYPE type, bool checkConditions = true);
+ virtual void ResetAnimation(ANIMATION_TYPE type);
+ virtual void ResetAnimations();
+
+ // push information updates
+ virtual void UpdateInfo(const CGUIListItem *item = NULL) {};
+ virtual void SetPushUpdates(bool pushUpdates) { m_pushedUpdates = pushUpdates; };
+
+ virtual bool IsGroup() const { return false; };
+ virtual bool IsContainer() const { return false; };
+ virtual bool GetCondition(int condition, int data) const { return false; };
+
+ void SetParentControl(CGUIControl *control) { m_parentControl = control; };
+ CGUIControl *GetParentControl(void) const { return m_parentControl; };
+ virtual void SaveStates(std::vector<CControlState> &states);
+
+ enum GUICONTROLTYPES {
+ GUICONTROL_UNKNOWN,
+ GUICONTROL_BUTTON,
+ GUICONTROL_CHECKMARK,
+ GUICONTROL_FADELABEL,
+ GUICONTROL_IMAGE,
+ GUICONTROL_BORDEREDIMAGE,
+ GUICONTROL_LARGE_IMAGE,
+ GUICONTROL_LABEL,
+ GUICONTROL_LIST,
+ GUICONTROL_LISTGROUP,
+ GUICONTROL_LISTEX,
+ GUICONTROL_PROGRESS,
+ GUICONTROL_RADIO,
+ GUICONTROL_RSS,
+ GUICONTROL_SELECTBUTTON,
+ GUICONTROL_SLIDER,
+ GUICONTROL_SETTINGS_SLIDER,
+ GUICONTROL_SPINBUTTON,
+ GUICONTROL_SPIN,
+ GUICONTROL_SPINEX,
+ GUICONTROL_TEXTBOX,
+ GUICONTROL_THUMBNAIL,
+ GUICONTROL_TOGGLEBUTTON,
+ GUICONTROL_VIDEO,
+ GUICONTROL_MOVER,
+ GUICONTROL_RESIZE,
+ GUICONTROL_BUTTONBAR,
+ GUICONTROL_CONSOLE,
+ GUICONTROL_EDIT,
+ GUICONTROL_VISUALISATION,
+ GUICONTROL_MULTI_IMAGE,
+ GUICONTROL_GROUP,
+ GUICONTROL_GROUPLIST,
+ GUICONTROL_SCROLLBAR,
+ GUICONTROL_LISTLABEL,
+ GUICONTROL_MULTISELECT,
+ GUICONTAINER_LIST,
+ GUICONTAINER_WRAPLIST,
+ GUICONTAINER_FIXEDLIST,
+ GUICONTAINER_PANEL
+ };
+ GUICONTROLTYPES GetControlType() const { return ControlType; }
+
+ enum GUIVISIBLE { HIDDEN = 0, DELAYED, VISIBLE };
+
+#ifdef _DEBUG
+ virtual void DumpTextureUse() {};
+#endif
+protected:
+ virtual void UpdateColors();
+ virtual void Animate(DWORD currentTime);
+ virtual bool CheckAnimation(ANIMATION_TYPE animType);
+ void UpdateStates(ANIMATION_TYPE type, ANIMATION_PROCESS currentProcess, ANIMATION_STATE currentState);
+ bool SendWindowMessage(CGUIMessage &message);
+
+ // navigation
+ int m_controlLeft;
+ int m_controlRight;
+ int m_controlUp;
+ int m_controlDown;
+ int m_controlNext;
+ int m_controlPrev;
+
+ std::vector<CGUIActionDescriptor> m_leftActions;
+ std::vector<CGUIActionDescriptor> m_rightActions;
+ std::vector<CGUIActionDescriptor> m_upActions;
+ std::vector<CGUIActionDescriptor> m_downActions;
+ std::vector<CGUIActionDescriptor> m_nextActions;
+ std::vector<CGUIActionDescriptor> m_prevActions;
+
+ float m_posX;
+ float m_posY;
+ float m_height;
+ float m_width;
+ CRect m_hitRect;
+ CGUIInfoColor m_diffuseColor;
+ int m_controlID;
+ int m_parentID;
+ bool m_bHasFocus;
+ bool m_bInvalidated;
+ bool m_bAllocated;
+ bool m_pulseOnSelect;
+ GUICONTROLTYPES ControlType;
+
+ CGUIControl *m_parentControl; // our parent control if we're part of a group
+
+ // visibility condition/state
+ int m_visibleCondition;
+ GUIVISIBLE m_visible;
+ bool m_visibleFromSkinCondition;
+ bool m_forceHidden; // set from the code when a hidden operation is given - overrides m_visible
+ CGUIInfoBool m_allowHiddenFocus;
+ bool m_hasRendered;
+ // enable/disable state
+ int m_enableCondition;
+ bool m_enabled;
+
+ bool m_pushedUpdates;
+
+ // animation effects
+ std::vector<CAnimation> m_animations;
+ CPoint m_camera;
+ bool m_hasCamera;
+ TransformMatrix m_transform;
+};
+
+#endif
diff --git a/guilib/GUIControlFactory.cpp b/guilib/GUIControlFactory.cpp
new file mode 100644
index 0000000000..28022b746c
--- /dev/null
+++ b/guilib/GUIControlFactory.cpp
@@ -0,0 +1,1415 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControlFactory.h"
+#include "LocalizeStrings.h"
+#include "GUIButtonControl.h"
+#include "GUIRadioButtonControl.h"
+#include "GUISpinControl.h"
+#include "GUIRSSControl.h"
+#include "GUIImage.h"
+#include "GUIBorderedImage.h"
+#include "GUILabelControl.h"
+#include "GUIEditControl.h"
+#include "GUIFadeLabelControl.h"
+#include "GUICheckMarkControl.h"
+#include "GUIToggleButtonControl.h"
+#include "GUITextBox.h"
+#include "GUIVideoControl.h"
+#include "GUIProgressControl.h"
+#include "GUISliderControl.h"
+#include "GUISelectButtonControl.h"
+#include "GUIMoverControl.h"
+#include "GUIResizeControl.h"
+#include "GUIButtonScroller.h"
+#include "GUISpinControlEx.h"
+#include "GUIVisualisationControl.h"
+#include "GUISettingsSliderControl.h"
+#include "GUIMultiImage.h"
+#include "GUIControlGroup.h"
+#include "GUIControlGroupList.h"
+#include "GUIScrollBarControl.h"
+#include "GUIListContainer.h"
+#include "GUIFixedListContainer.h"
+#include "GUIWrappingListContainer.h"
+#include "GUIPanelContainer.h"
+#include "GUIMultiSelectText.h"
+#include "GUIListLabel.h"
+#include "GUIListGroup.h"
+#include "utils/GUIInfoManager.h"
+#include "utils/CharsetConverter.h"
+#include "utils/log.h"
+#include "ButtonTranslator.h"
+#include "XMLUtils.h"
+#include "GUIFontManager.h"
+#include "GUIColorManager.h"
+#include "SkinInfo.h"
+#include "Settings.h"
+#include "StringUtils.h"
+
+using namespace std;
+
+CGUIControlFactory::CGUIControlFactory(void)
+{}
+
+CGUIControlFactory::~CGUIControlFactory(void)
+{}
+
+bool CGUIControlFactory::GetIntRange(const TiXmlNode* pRootNode, const char* strTag, int& iMinValue, int& iMaxValue, int& iIntervalValue)
+{
+ const TiXmlNode* pNode = pRootNode->FirstChild(strTag);
+ if (!pNode || !pNode->FirstChild()) return false;
+ iMinValue = atoi(pNode->FirstChild()->Value());
+ const char* maxValue = strchr(pNode->FirstChild()->Value(), ',');
+ if (maxValue)
+ {
+ maxValue++;
+ iMaxValue = atoi(maxValue);
+
+ const char* intervalValue = strchr(maxValue, ',');
+ if (intervalValue)
+ {
+ intervalValue++;
+ iIntervalValue = atoi(intervalValue);
+ }
+ }
+
+ return true;
+}
+
+bool CGUIControlFactory::GetFloatRange(const TiXmlNode* pRootNode, const char* strTag, float& fMinValue, float& fMaxValue, float& fIntervalValue)
+{
+ const TiXmlNode* pNode = pRootNode->FirstChild(strTag);
+ if (!pNode || !pNode->FirstChild()) return false;
+ fMinValue = (float)atof(pNode->FirstChild()->Value());
+ const char* maxValue = strchr(pNode->FirstChild()->Value(), ',');
+ if (maxValue)
+ {
+ maxValue++;
+ fMaxValue = (float)atof(maxValue);
+
+ const char* intervalValue = strchr(maxValue, ',');
+ if (intervalValue)
+ {
+ intervalValue++;
+ fIntervalValue = (float)atof(intervalValue);
+ }
+ }
+
+ return true;
+}
+
+bool CGUIControlFactory::GetFloat(const TiXmlNode* pRootNode, const char* strTag, float& value)
+{
+ const TiXmlNode* pNode = pRootNode->FirstChild(strTag );
+ if (!pNode || !pNode->FirstChild()) return false;
+ return g_SkinInfo.ResolveConstant(pNode->FirstChild()->Value(), value);
+}
+
+bool CGUIControlFactory::GetDWORD(const TiXmlNode* pRootNode, const char* strTag, DWORD &value)
+{
+ const TiXmlNode* pNode = pRootNode->FirstChild(strTag );
+ if (!pNode || !pNode->FirstChild()) return false;
+ return g_SkinInfo.ResolveConstant(pNode->FirstChild()->Value(), value);
+}
+
+bool CGUIControlFactory::GetMultipleString(const TiXmlNode* pRootNode, const char* strTag, std::vector<CGUIActionDescriptor>& vecStringValue)
+{
+ const TiXmlNode* pNode = pRootNode->FirstChild(strTag );
+ if (!pNode) return false;
+ vecStringValue.clear();
+ bool bFound = false;
+ while (pNode)
+ {
+ CGUIActionDescriptor action;
+ if (CGUIControlFactory::GetAction((const TiXmlElement*) pNode, action))
+ {
+ vecStringValue.push_back(action);
+ bFound = true;
+ }
+ pNode = pNode->NextSibling(strTag);
+ }
+ return bFound;
+}
+
+bool CGUIControlFactory::GetAction(const TiXmlElement* pElement, CGUIActionDescriptor &action)
+{
+ CStdString langStr = pElement->Attribute("lang");
+ if (langStr.CompareNoCase("python") == 0 )
+ action.m_lang = CGUIActionDescriptor::LANG_PYTHON;
+ else
+ action.m_lang = CGUIActionDescriptor::LANG_XBMC;
+
+ if (pElement->FirstChild())
+ {
+ action.m_action = pElement->FirstChild()->Value();
+ return true;
+ }
+ else
+ {
+ action.m_action = "";
+ return false;
+ }
+}
+
+bool CGUIControlFactory::GetAspectRatio(const TiXmlNode* pRootNode, const char* strTag, CAspectRatio &aspect)
+{
+ CStdString ratio;
+ const TiXmlElement *node = pRootNode->FirstChildElement(strTag);
+ if (!node || !node->FirstChild())
+ return false;
+
+ ratio = node->FirstChild()->Value();
+ if (ratio.CompareNoCase("keep") == 0) aspect.ratio = CAspectRatio::AR_KEEP;
+ else if (ratio.CompareNoCase("scale") == 0) aspect.ratio = CAspectRatio::AR_SCALE;
+ else if (ratio.CompareNoCase("center") == 0) aspect.ratio = CAspectRatio::AR_CENTER;
+ else if (ratio.CompareNoCase("stretch") == 0) aspect.ratio = CAspectRatio::AR_STRETCH;
+
+ const char *attribute = node->Attribute("align");
+ if (attribute)
+ {
+ CStdString align(attribute);
+ if (align.CompareNoCase("center") == 0) aspect.align = ASPECT_ALIGN_CENTER | (aspect.align & ASPECT_ALIGNY_MASK);
+ else if (align.CompareNoCase("right") == 0) aspect.align = ASPECT_ALIGN_RIGHT | (aspect.align & ASPECT_ALIGNY_MASK);
+ else if (align.CompareNoCase("left") == 0) aspect.align = ASPECT_ALIGN_LEFT | (aspect.align & ASPECT_ALIGNY_MASK);
+ }
+ attribute = node->Attribute("aligny");
+ if (attribute)
+ {
+ CStdString align(attribute);
+ if (align.CompareNoCase("center") == 0) aspect.align = ASPECT_ALIGNY_CENTER | (aspect.align & ASPECT_ALIGN_MASK);
+ else if (align.CompareNoCase("bottom") == 0) aspect.align = ASPECT_ALIGNY_BOTTOM | (aspect.align & ASPECT_ALIGN_MASK);
+ else if (align.CompareNoCase("top") == 0) aspect.align = ASPECT_ALIGNY_TOP | (aspect.align & ASPECT_ALIGN_MASK);
+ }
+ attribute = node->Attribute("scalediffuse");
+ if (attribute)
+ {
+ CStdString scale(attribute);
+ if (scale.CompareNoCase("true") == 0 || scale.CompareNoCase("yes") == 0)
+ aspect.scaleDiffuse = true;
+ else
+ aspect.scaleDiffuse = false;
+ }
+ return true;
+}
+
+bool CGUIControlFactory::GetInfoTexture(const TiXmlNode* pRootNode, const char* strTag, CTextureInfo &image, CGUIInfoLabel &info)
+{
+ GetTexture(pRootNode, strTag, image);
+ image.filename = "";
+ GetInfoLabel(pRootNode, strTag, info);
+ return true;
+}
+
+bool CGUIControlFactory::GetTexture(const TiXmlNode* pRootNode, const char* strTag, CTextureInfo &image)
+{
+ const TiXmlElement* pNode = pRootNode->FirstChildElement(strTag);
+ if (!pNode) return false;
+ const char *border = pNode->Attribute("border");
+ if (border)
+ GetRectFromString(border, image.border);
+ image.orientation = 0;
+ const char *flipX = pNode->Attribute("flipx");
+ if (flipX && strcmpi(flipX, "true") == 0) image.orientation = 1;
+ const char *flipY = pNode->Attribute("flipy");
+ if (flipY && strcmpi(flipY, "true") == 0) image.orientation = 3 - image.orientation; // either 3 or 2
+ image.diffuse = pNode->Attribute("diffuse");
+ const char *background = pNode->Attribute("background");
+ if (background && strnicmp(background, "true", 4) == 0)
+ image.useLarge = true;
+ image.filename = (pNode->FirstChild() && pNode->FirstChild()->ValueStr() != "-") ? pNode->FirstChild()->Value() : "";
+ return true;
+}
+
+void CGUIControlFactory::GetRectFromString(const CStdString &string, FRECT &rect)
+{
+ // format is rect="left,right,top,bottom"
+ CStdStringArray strRect;
+ StringUtils::SplitString(string, ",", strRect);
+ if (strRect.size() == 1)
+ {
+ g_SkinInfo.ResolveConstant(strRect[0], rect.left);
+ rect.top = rect.left;
+ rect.right = rect.left;
+ rect.bottom = rect.left;
+ }
+ else if (strRect.size() == 4)
+ {
+ g_SkinInfo.ResolveConstant(strRect[0], rect.left);
+ g_SkinInfo.ResolveConstant(strRect[1], rect.top);
+ g_SkinInfo.ResolveConstant(strRect[2], rect.right);
+ g_SkinInfo.ResolveConstant(strRect[3], rect.bottom);
+ }
+}
+
+bool CGUIControlFactory::GetAlignment(const TiXmlNode* pRootNode, const char* strTag, uint32_t& alignment)
+{
+ const TiXmlNode* pNode = pRootNode->FirstChild(strTag);
+ if (!pNode || !pNode->FirstChild()) return false;
+
+ CStdString strAlign = pNode->FirstChild()->Value();
+ if (strAlign == "right" || strAlign == "bottom") alignment = XBFONT_RIGHT;
+ else if (strAlign == "center") alignment = XBFONT_CENTER_X;
+ else if (strAlign == "justify") alignment = XBFONT_JUSTIFIED;
+ else alignment = XBFONT_LEFT;
+ return true;
+}
+
+bool CGUIControlFactory::GetAlignmentY(const TiXmlNode* pRootNode, const char* strTag, uint32_t& alignment)
+{
+ const TiXmlNode* pNode = pRootNode->FirstChild(strTag );
+ if (!pNode || !pNode->FirstChild())
+ {
+ return false;
+ }
+
+ CStdString strAlign = pNode->FirstChild()->Value();
+
+ alignment = 0;
+ if (strAlign == "center")
+ {
+ alignment = XBFONT_CENTER_Y;
+ }
+
+ return true;
+}
+
+bool CGUIControlFactory::GetConditionalVisibility(const TiXmlNode* control, int &condition, CGUIInfoBool &allowHiddenFocus)
+{
+ const TiXmlElement* node = control->FirstChildElement("visible");
+ if (!node) return false;
+ vector<CStdString> conditions;
+ while (node)
+ {
+ const char *hidden = node->Attribute("allowhiddenfocus");
+ if (hidden)
+ allowHiddenFocus.Parse(hidden);
+ // add to our condition string
+ if (!node->NoChildren())
+ conditions.push_back(node->FirstChild()->Value());
+ node = node->NextSiblingElement("visible");
+ }
+ if (!conditions.size())
+ return false;
+ if (conditions.size() == 1)
+ condition = g_infoManager.TranslateString(conditions[0]);
+ else
+ { // multiple conditions should be anded together
+ CStdString conditionString = "[";
+ for (unsigned int i = 0; i < conditions.size() - 1; i++)
+ conditionString += conditions[i] + "] + [";
+ conditionString += conditions[conditions.size() - 1] + "]";
+ condition = g_infoManager.TranslateString(conditionString);
+ }
+ return (condition != 0);
+}
+
+bool CGUIControlFactory::GetCondition(const TiXmlNode *control, const char *tag, int &condition)
+{
+ CStdString condString;
+ if (XMLUtils::GetString(control, tag, condString))
+ {
+ condition = g_infoManager.TranslateString(condString);
+ return true;
+ }
+ return false;
+}
+
+bool CGUIControlFactory::GetConditionalVisibility(const TiXmlNode *control, int &condition)
+{
+ CGUIInfoBool allowHiddenFocus;
+ return GetConditionalVisibility(control, condition, allowHiddenFocus);
+}
+
+bool CGUIControlFactory::GetAnimations(const TiXmlNode *control, const FRECT &rect, vector<CAnimation> &animations)
+{
+ const TiXmlElement* node = control->FirstChildElement("animation");
+ bool ret = false;
+ if (node)
+ animations.clear();
+ while (node)
+ {
+ ret = true;
+ if (node->FirstChild())
+ {
+ CAnimation anim;
+ anim.Create(node, rect);
+ animations.push_back(anim);
+ if (strcmpi(node->FirstChild()->Value(), "VisibleChange") == 0)
+ { // add the hidden one as well
+ TiXmlElement hidden(*node);
+ hidden.FirstChild()->SetValue("hidden");
+ const char *start = hidden.Attribute("start");
+ const char *end = hidden.Attribute("end");
+ if (start && end)
+ {
+ CStdString temp = end;
+ hidden.SetAttribute("end", start);
+ hidden.SetAttribute("start", temp.c_str());
+ }
+ else if (start)
+ hidden.SetAttribute("end", start);
+ else if (end)
+ hidden.SetAttribute("start", end);
+ CAnimation anim2;
+ anim2.Create(&hidden, rect);
+ animations.push_back(anim2);
+ }
+ }
+ node = node->NextSiblingElement("animation");
+ }
+ return ret;
+}
+
+bool CGUIControlFactory::GetHitRect(const TiXmlNode *control, CRect &rect)
+{
+ const TiXmlElement* node = control->FirstChildElement("hitrect");
+ if (node)
+ {
+ if (node->Attribute("x")) g_SkinInfo.ResolveConstant(node->Attribute("x"), rect.x1);
+ if (node->Attribute("y")) g_SkinInfo.ResolveConstant(node->Attribute("y"), rect.y1);
+ if (node->Attribute("w"))
+ {
+ g_SkinInfo.ResolveConstant(node->Attribute("w"), rect.x2);
+ rect.x2 += rect.x1;
+ }
+ if (node->Attribute("h"))
+ {
+ g_SkinInfo.ResolveConstant(node->Attribute("h"), rect.y2);
+ rect.y2 += rect.y1;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool CGUIControlFactory::GetColor(const TiXmlNode *control, const char *strTag, color_t &value)
+{
+ const TiXmlElement* node = control->FirstChildElement(strTag);
+ if (node && node->FirstChild())
+ {
+ value = g_colorManager.GetColor(node->FirstChild()->Value());
+ return true;
+ }
+ return false;
+}
+
+bool CGUIControlFactory::GetInfoColor(const TiXmlNode *control, const char *strTag, CGUIInfoColor &value)
+{
+ const TiXmlElement* node = control->FirstChildElement(strTag);
+ if (node && node->FirstChild())
+ {
+ value.Parse(node->FirstChild()->Value());
+ return true;
+ }
+ return false;
+}
+
+bool CGUIControlFactory::GetNavigation(const TiXmlElement *node, const char *tag, int &direction, vector<CGUIActionDescriptor> &actions)
+{
+ if (!GetMultipleString(node, tag, actions))
+ return false; // no tag specified
+ if (actions.size() == 1 && StringUtils::IsNaturalNumber(actions[0].m_action))
+ { // single numeric tag specified
+ direction = atol(actions[0].m_action.c_str());
+ actions.clear();
+ }
+ else
+ direction = 0;
+ return true;
+}
+
+void CGUIControlFactory::GetInfoLabel(const TiXmlNode *pControlNode, const CStdString &labelTag, CGUIInfoLabel &infoLabel)
+{
+ vector<CGUIInfoLabel> labels;
+ GetInfoLabels(pControlNode, labelTag, labels);
+ if (labels.size())
+ infoLabel = labels[0];
+}
+
+void CGUIControlFactory::GetInfoLabels(const TiXmlNode *pControlNode, const CStdString &labelTag, vector<CGUIInfoLabel> &infoLabels)
+{
+ // we can have the following infolabels:
+ // 1. <number>1234</number> -> direct number
+ // 2. <label>number</label> -> lookup in localizestrings
+ // 3. <label fallback="blah">$LOCALIZE(blah) $INFO(blah)</label> -> infolabel with given fallback
+ // 4. <info>ListItem.Album</info> (uses <label> as fallback)
+ int labelNumber = 0;
+ if (XMLUtils::GetInt(pControlNode, "number", labelNumber))
+ {
+ CStdString label;
+ label.Format("%i", labelNumber);
+ infoLabels.push_back(CGUIInfoLabel(label));
+ return; // done
+ }
+ const TiXmlElement *labelNode = pControlNode->FirstChildElement(labelTag);
+ while (labelNode)
+ {
+ if (labelNode->FirstChild())
+ {
+ CStdString label = labelNode->FirstChild()->Value();
+ CStdString fallback = labelNode->Attribute("fallback");
+ if (label.size() && label[0] != '-')
+ {
+ if (StringUtils::IsNaturalNumber(label))
+ label = g_localizeStrings.Get(atoi(label));
+ else // we assume the skin xml's aren't encoded as UTF-8
+ g_charsetConverter.unknownToUTF8(label);
+ if (StringUtils::IsNaturalNumber(fallback))
+ fallback = g_localizeStrings.Get(atoi(fallback));
+ else
+ g_charsetConverter.unknownToUTF8(fallback);
+ infoLabels.push_back(CGUIInfoLabel(label, fallback));
+ }
+ }
+ labelNode = labelNode->NextSiblingElement(labelTag);
+ }
+ const TiXmlNode *infoNode = pControlNode->FirstChild("info");
+ if (infoNode)
+ { // <info> nodes override <label>'s (backward compatibility)
+ CStdString fallback;
+ if (infoLabels.size())
+ fallback = infoLabels[0].GetLabel(0);
+ infoLabels.clear();
+ while (infoNode)
+ {
+ if (infoNode->FirstChild())
+ {
+ CStdString info;
+ info.Format("$INFO[%s]", infoNode->FirstChild()->Value());
+ infoLabels.push_back(CGUIInfoLabel(info, fallback));
+ }
+ infoNode = infoNode->NextSibling("info");
+ }
+ }
+}
+
+// Convert a string to a GUI label, by translating/parsing the label for localisable strings
+CStdString CGUIControlFactory::FilterLabel(const CStdString &label)
+{
+ CStdString viewLabel = label;
+ if (StringUtils::IsNaturalNumber(viewLabel))
+ viewLabel = g_localizeStrings.Get(atoi(label));
+ else
+ g_charsetConverter.unknownToUTF8(viewLabel);
+ return viewLabel;
+}
+
+bool CGUIControlFactory::GetString(const TiXmlNode* pRootNode, const char *strTag, CStdString &text)
+{
+ if (!XMLUtils::GetString(pRootNode, strTag, text))
+ return false;
+ if (text == "-")
+ text.Empty();
+ if (StringUtils::IsNaturalNumber(text))
+ text = g_localizeStrings.Get(atoi(text.c_str()));
+ else
+ g_charsetConverter.unknownToUTF8(text);
+ return true;
+}
+
+CStdString CGUIControlFactory::GetType(const TiXmlElement *pControlNode)
+{
+ CStdString type;
+ const char *szType = pControlNode->Attribute("type");
+ if (szType)
+ type = szType;
+ else // backward compatibility - not desired
+ XMLUtils::GetString(pControlNode, "type", type);
+ return type;
+}
+
+CGUIControl* CGUIControlFactory::Create(int parentID, const FRECT &rect, TiXmlElement* pControlNode, bool insideContainer)
+{
+ // resolve any <include> tag's in this control
+ g_SkinInfo.ResolveIncludes(pControlNode);
+
+ // get the control type
+ CStdString strType = GetType(pControlNode);
+
+ // resolve again with strType set so that <default> tags are added
+ g_SkinInfo.ResolveIncludes(pControlNode, strType);
+
+ int id = 0;
+ float posX = 0, posY = 0;
+ float width = 0, height = 0;
+
+ int left = 0, right = 0, up = 0, down = 0, next = 0, prev = 0;
+ vector<CGUIActionDescriptor> leftActions, rightActions, upActions, downActions, nextActions, prevActions;
+
+ int pageControl = 0;
+ CGUIInfoColor colorDiffuse(0xFFFFFFFF);
+ int defaultControl = 0;
+ bool defaultAlways = false;
+ CStdString strTmp;
+ int singleInfo = 0;
+ CStdString strLabel;
+ int iUrlSet=0;
+ int iToggleSelect;
+
+ float spinWidth = 16;
+ float spinHeight = 16;
+ float spinPosX = 0, spinPosY = 0;
+ float checkWidth = 0, checkHeight = 0;
+ CStdString strSubType;
+ int iType = SPIN_CONTROL_TYPE_TEXT;
+ int iMin = 0;
+ int iMax = 100;
+ int iInterval = 1;
+ float fMin = 0.0f;
+ float fMax = 1.0f;
+ float fInterval = 0.1f;
+ bool bReverse = true;
+ bool bReveal = false;
+ CTextureInfo textureBackground, textureLeft, textureRight, textureMid, textureOverlay;
+ float rMin = 0.0f;
+ float rMax = 100.0f;
+ CTextureInfo textureNib, textureNibFocus, textureBar, textureBarFocus;
+ CTextureInfo textureLeftFocus, textureRightFocus;
+ CTextureInfo textureUp, textureDown;
+ CTextureInfo textureUpFocus, textureDownFocus;
+ CTextureInfo texture, borderTexture;
+ CGUIInfoLabel textureFile;
+ CTextureInfo textureCheckMark, textureCheckMarkNF;
+ CTextureInfo textureFocus, textureNoFocus;
+ CTextureInfo textureAltFocus, textureAltNoFocus;
+ CTextureInfo textureRadioOn, textureRadioOff;
+ CTextureInfo imageNoFocus, imageFocus;
+ CGUIInfoLabel texturePath;
+ FRECT borderSize = { 0, 0, 0, 0};
+
+ float itemWidth = 16, itemHeight = 16;
+ float sliderWidth = 150, sliderHeight = 16;
+ float textureWidthBig = 128;
+ float textureHeightBig = 128;
+ float textureHeight = 30;
+ float textureWidth = 80;
+ float itemWidthBig = 150;
+ float itemHeightBig = 150;
+
+ float spaceBetweenItems = 2;
+ bool bHasPath = false;
+ vector<CGUIActionDescriptor> clickActions;
+ vector<CGUIActionDescriptor> altclickActions;
+ vector<CGUIActionDescriptor> focusActions;
+ vector<CGUIActionDescriptor> unfocusActions;
+ vector<CGUIActionDescriptor> textChangeActions;
+ CStdString strTitle = "";
+ CStdString strRSSTags = "";
+
+ float thumbXPos = 4;
+ float thumbYPos = 10;
+ float thumbWidth = 64;
+ float thumbHeight = 64;
+
+ float thumbXPosBig = 14;
+ float thumbYPosBig = 14;
+ float thumbWidthBig = 100;
+ float thumbHeightBig = 100;
+ int iNumSlots = 7;
+ float buttonGap = 5;
+ int iDefaultSlot = 2;
+ int iMovementRange = 2;
+ bool bHorizontal = false;
+ int iAlpha = 0;
+ bool bWrapAround = true;
+ bool bSmoothScrolling = true;
+ CAspectRatio aspect;
+#ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY
+ if (insideContainer) // default for inside containers is keep
+ aspect.ratio = CAspectRatio::AR_KEEP;
+#endif
+
+ int iVisibleCondition = 0;
+ CGUIInfoBool allowHiddenFocus(false);
+ int enableCondition = 0;
+
+ vector<CAnimation> animations;
+
+ bool bScrollLabel = false;
+ bool bPulse = true;
+ DWORD timePerImage = 0;
+ DWORD fadeTime = 0;
+ DWORD timeToPauseAtEnd = 0;
+ bool randomized = false;
+ bool loop = true;
+ bool wrapMultiLine = false;
+ ORIENTATION orientation = VERTICAL;
+ bool showOnePage = true;
+ bool scrollOut = true;
+ int preloadItems = 0;
+
+ CLabelInfo labelInfo;
+ CLabelInfo labelInfo2;
+ CLabelInfo spinInfo;
+
+ CGUIInfoColor textColor3;
+
+ float radioWidth = 0;
+ float radioHeight = 0;
+ float radioPosX = 0;
+ float radioPosY = 0;
+
+ CStdString altLabel;
+ CStdString strLabel2;
+
+ int focusPosition = 0;
+ int scrollTime = 200;
+ bool useControlCoords = false;
+ bool renderFocusedLast = false;
+
+ CRect hitRect;
+ CPoint camera;
+ bool hasCamera = false;
+ int scrollSpeed = CScrollInfo::defaultSpeed;
+ bool resetOnLabelChange = true;
+ bool bPassword = false;
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Read control properties from XML
+ //
+
+ if (!pControlNode->Attribute("id", (int*) &id))
+ XMLUtils::GetInt(pControlNode, "id", (int&) id); // backward compatibility - not desired
+ // TODO: Perhaps we should check here whether id is valid for focusable controls
+ // such as buttons etc. For labels/fadelabels/images it does not matter
+
+ GetFloat(pControlNode, "posx", posX);
+ GetFloat(pControlNode, "posy", posY);
+ // Convert these from relative coords
+ CStdString pos;
+ XMLUtils::GetString(pControlNode, "posx", pos);
+ if (pos.Right(1) == "r")
+ posX = (rect.right - rect.left) - posX;
+ XMLUtils::GetString(pControlNode, "posy", pos);
+ if (pos.Right(1) == "r")
+ posY = (rect.bottom - rect.top) - posY;
+
+ GetFloat(pControlNode, "width", width);
+ GetFloat(pControlNode, "height", height);
+
+ // adjust width and height accordingly for groups. Groups should
+ // take the width/height of the parent (adjusted for positioning)
+ // if none is defined.
+ if (strType == "group" || strType == "grouplist")
+ {
+ if (!width)
+ width = max(rect.right - posX, 0.0f);
+ if (!height)
+ height = max(rect.bottom - posY, 0.0f);
+ }
+
+ hitRect.SetRect(posX, posY, posX + width, posY + height);
+ GetHitRect(pControlNode, hitRect);
+
+ if (!GetNavigation(pControlNode, "onup", up, upActions)) up = id - 1;
+ if (!GetNavigation(pControlNode, "ondown", down, downActions)) down = id + 1;
+ if (!GetNavigation(pControlNode, "onleft", left, leftActions)) left = id;
+ if (!GetNavigation(pControlNode, "onright", right, rightActions)) right = id;
+ if (!GetNavigation(pControlNode, "onnext", next, nextActions)) next = id;
+ if (!GetNavigation(pControlNode, "onprev", prev, prevActions)) prev = id;
+
+ if (XMLUtils::GetInt(pControlNode, "defaultcontrol", defaultControl))
+ {
+ const char *always = pControlNode->FirstChildElement("defaultcontrol")->Attribute("always");
+ if (always && strnicmp(always, "true", 4) == 0)
+ defaultAlways = true;
+ }
+ XMLUtils::GetInt(pControlNode, "pagecontrol", pageControl);
+
+ GetInfoColor(pControlNode, "colordiffuse", colorDiffuse);
+
+ GetConditionalVisibility(pControlNode, iVisibleCondition, allowHiddenFocus);
+ GetCondition(pControlNode, "enable", enableCondition);
+
+ // note: animrect here uses .right and .bottom as width and height respectively (nonstandard)
+ FRECT animRect = { posX, posY, width, height };
+ GetAnimations(pControlNode, animRect, animations);
+
+ GetInfoColor(pControlNode, "textcolor", labelInfo.textColor);
+ GetInfoColor(pControlNode, "focusedcolor", labelInfo.focusedColor);
+ GetInfoColor(pControlNode, "disabledcolor", labelInfo.disabledColor);
+ GetInfoColor(pControlNode, "shadowcolor", labelInfo.shadowColor);
+ GetInfoColor(pControlNode, "selectedcolor", labelInfo.selectedColor);
+ GetFloat(pControlNode, "textoffsetx", labelInfo.offsetX);
+ GetFloat(pControlNode, "textoffsety", labelInfo.offsetY);
+ GetFloat(pControlNode, "textxoff", labelInfo.offsetX);
+ GetFloat(pControlNode, "textyoff", labelInfo.offsetY);
+ GetFloat(pControlNode, "textxoff2", labelInfo2.offsetX);
+ GetFloat(pControlNode, "textyoff2", labelInfo2.offsetY);
+ int angle = 0; // use the negative angle to compensate for our vertically flipped cartesian plane
+ if (XMLUtils::GetInt(pControlNode, "angle", angle)) labelInfo.angle = (float)-angle;
+ CStdString strFont;
+ if (XMLUtils::GetString(pControlNode, "font", strFont))
+ labelInfo.font = g_fontManager.GetFont(strFont);
+ GetAlignment(pControlNode, "align", labelInfo.align);
+ uint32_t alignY = 0;
+ if (GetAlignmentY(pControlNode, "aligny", alignY))
+ labelInfo.align |= alignY;
+ if (GetFloat(pControlNode, "textwidth", labelInfo.width))
+ labelInfo.align |= XBFONT_TRUNCATED;
+ labelInfo2.selectedColor = labelInfo.selectedColor;
+ GetInfoColor(pControlNode, "selectedcolor2", labelInfo2.selectedColor);
+ GetInfoColor(pControlNode, "textcolor2", labelInfo2.textColor);
+ GetInfoColor(pControlNode, "focusedcolor2", labelInfo2.focusedColor);
+ labelInfo2.font = labelInfo.font;
+ if (XMLUtils::GetString(pControlNode, "font2", strFont))
+ labelInfo2.font = g_fontManager.GetFont(strFont);
+
+ GetMultipleString(pControlNode, "onclick", clickActions);
+ GetMultipleString(pControlNode, "ontextchange", textChangeActions);
+ GetMultipleString(pControlNode, "onfocus", focusActions);
+ GetMultipleString(pControlNode, "onunfocus", unfocusActions);
+ GetMultipleString(pControlNode, "altclick", altclickActions);
+
+ CStdString infoString;
+ if (XMLUtils::GetString(pControlNode, "info", infoString))
+ singleInfo = g_infoManager.TranslateString(infoString);
+
+ GetTexture(pControlNode, "texturefocus", textureFocus);
+ GetTexture(pControlNode, "texturenofocus", textureNoFocus);
+ GetTexture(pControlNode, "alttexturefocus", textureAltFocus);
+ GetTexture(pControlNode, "alttexturenofocus", textureAltNoFocus);
+ CStdString strToggleSelect;
+ XMLUtils::GetString(pControlNode, "usealttexture", strToggleSelect);
+ XMLUtils::GetString(pControlNode, "selected", strToggleSelect);
+ iToggleSelect = g_infoManager.TranslateString(strToggleSelect);
+
+ XMLUtils::GetBoolean(pControlNode, "haspath", bHasPath);
+
+ GetTexture(pControlNode, "textureup", textureUp);
+ GetTexture(pControlNode, "texturedown", textureDown);
+ GetTexture(pControlNode, "textureupfocus", textureUpFocus);
+ GetTexture(pControlNode, "texturedownfocus", textureDownFocus);
+
+ GetTexture(pControlNode, "textureleft", textureLeft);
+ GetTexture(pControlNode, "textureright", textureRight);
+ GetTexture(pControlNode, "textureleftfocus", textureLeftFocus);
+ GetTexture(pControlNode, "texturerightfocus", textureRightFocus);
+
+ GetInfoColor(pControlNode, "spincolor", spinInfo.textColor);
+ if (XMLUtils::GetString(pControlNode, "spinfont", strFont))
+ spinInfo.font = g_fontManager.GetFont(strFont);
+ if (!spinInfo.font) spinInfo.font = labelInfo.font;
+
+ GetFloat(pControlNode, "spinwidth", spinWidth);
+ GetFloat(pControlNode, "spinheight", spinHeight);
+ GetFloat(pControlNode, "spinposx", spinPosX);
+ GetFloat(pControlNode, "spinposy", spinPosY);
+
+ GetFloat(pControlNode, "markwidth", checkWidth);
+ GetFloat(pControlNode, "markheight", checkHeight);
+ GetFloat(pControlNode, "sliderwidth", sliderWidth);
+ GetFloat(pControlNode, "sliderheight", sliderHeight);
+ GetTexture(pControlNode, "texturecheckmark", textureCheckMark);
+ GetTexture(pControlNode, "texturecheckmarknofocus", textureCheckMarkNF);
+ GetTexture(pControlNode, "textureradiofocus", textureRadioOn); // backward compatibility
+ GetTexture(pControlNode, "textureradionofocus", textureRadioOff);
+ GetTexture(pControlNode, "textureradioon", textureRadioOn);
+ GetTexture(pControlNode, "textureradiooff", textureRadioOff);
+
+ GetTexture(pControlNode, "texturesliderbackground", textureBackground);
+ GetTexture(pControlNode, "texturesliderbar", textureBar);
+ GetTexture(pControlNode, "texturesliderbarfocus", textureBarFocus);
+ GetTexture(pControlNode, "textureslidernib", textureNib);
+ GetTexture(pControlNode, "textureslidernibfocus", textureNibFocus);
+
+ XMLUtils::GetString(pControlNode, "title", strTitle);
+ XMLUtils::GetString(pControlNode, "tagset", strRSSTags);
+ GetInfoColor(pControlNode, "headlinecolor", labelInfo2.textColor);
+ GetInfoColor(pControlNode, "titlecolor", textColor3);
+
+ if (XMLUtils::GetString(pControlNode, "subtype", strSubType))
+ {
+ strSubType.ToLower();
+
+ if ( strSubType == "int")
+ iType = SPIN_CONTROL_TYPE_INT;
+ else if ( strSubType == "page")
+ iType = SPIN_CONTROL_TYPE_PAGE;
+ else if ( strSubType == "float")
+ iType = SPIN_CONTROL_TYPE_FLOAT;
+ else
+ iType = SPIN_CONTROL_TYPE_TEXT;
+ }
+
+ if (!GetIntRange(pControlNode, "range", iMin, iMax, iInterval))
+ {
+ GetFloatRange(pControlNode, "range", fMin, fMax, fInterval);
+ }
+
+ XMLUtils::GetBoolean(pControlNode, "reverse", bReverse);
+ XMLUtils::GetBoolean(pControlNode, "reveal", bReveal);
+
+ GetTexture(pControlNode, "texturebg", textureBackground);
+ GetTexture(pControlNode, "lefttexture", textureLeft);
+ GetTexture(pControlNode, "midtexture", textureMid);
+ GetTexture(pControlNode, "righttexture", textureRight);
+ GetTexture(pControlNode, "overlaytexture", textureOverlay);
+
+ // the <texture> tag can be overridden by the <info> tag
+ GetInfoTexture(pControlNode, "texture", texture, textureFile);
+
+ GetTexture(pControlNode, "bordertexture", borderTexture);
+ GetFloat(pControlNode, "rangemin", rMin);
+ GetFloat(pControlNode, "rangemax", rMax);
+
+ GetFloat(pControlNode, "itemwidth", itemWidth);
+ GetFloat(pControlNode, "itemheight", itemHeight);
+ GetFloat(pControlNode, "spacebetweenitems", spaceBetweenItems);
+
+ GetTexture(pControlNode, "imagefolder", imageNoFocus);
+ GetTexture(pControlNode, "imagefolderfocus", imageFocus);
+ GetFloat(pControlNode, "texturewidth", textureWidth);
+ GetFloat(pControlNode, "textureheight", textureHeight);
+
+ GetFloat(pControlNode, "thumbwidth", thumbWidth);
+ GetFloat(pControlNode, "thumbheight", thumbHeight);
+ GetFloat(pControlNode, "thumbposx", thumbXPos);
+ GetFloat(pControlNode, "thumbposy", thumbYPos);
+
+ GetFloat(pControlNode, "thumbwidthbig", thumbWidthBig);
+ GetFloat(pControlNode, "thumbheightbig", thumbHeightBig);
+ GetFloat(pControlNode, "thumbposxbig", thumbXPosBig);
+ GetFloat(pControlNode, "thumbposybig", thumbYPosBig);
+
+ GetFloat(pControlNode, "texturewidthbig", textureWidthBig);
+ GetFloat(pControlNode, "textureheightbig", textureHeightBig);
+ GetFloat(pControlNode, "itemwidthbig", itemWidthBig);
+ GetFloat(pControlNode, "itemheightbig", itemHeightBig);
+
+ // fade label can have a whole bunch, but most just have one
+ vector<CGUIInfoLabel> infoLabels;
+ GetInfoLabels(pControlNode, "label", infoLabels);
+
+ GetString(pControlNode, "label", strLabel);
+ GetString(pControlNode, "altlabel", altLabel);
+ GetString(pControlNode, "label2", strLabel2);
+
+ XMLUtils::GetBoolean(pControlNode, "wrapmultiline", wrapMultiLine);
+ XMLUtils::GetInt(pControlNode,"urlset",iUrlSet);
+
+ // stuff for button scroller
+ if ( XMLUtils::GetString(pControlNode, "orientation", strTmp) )
+ {
+ if (strTmp.ToLower() == "horizontal")
+ {
+ bHorizontal = true;
+ orientation = HORIZONTAL;
+ }
+ }
+ GetFloat(pControlNode, "buttongap", buttonGap);
+ GetFloat(pControlNode, "itemgap", buttonGap);
+ XMLUtils::GetInt(pControlNode, "numbuttons", iNumSlots);
+ XMLUtils::GetInt(pControlNode, "movement", iMovementRange);
+ XMLUtils::GetInt(pControlNode, "defaultbutton", iDefaultSlot);
+ XMLUtils::GetInt(pControlNode, "alpha", iAlpha);
+ XMLUtils::GetBoolean(pControlNode, "wraparound", bWrapAround);
+ XMLUtils::GetBoolean(pControlNode, "smoothscrolling", bSmoothScrolling);
+ GetAspectRatio(pControlNode, "aspectratio", aspect);
+ XMLUtils::GetBoolean(pControlNode, "scroll", bScrollLabel);
+ XMLUtils::GetBoolean(pControlNode,"pulseonselect", bPulse);
+
+ GetInfoTexture(pControlNode, "imagepath", texture, texturePath);
+
+ GetDWORD(pControlNode,"timeperimage", timePerImage);
+ GetDWORD(pControlNode,"fadetime", fadeTime);
+ GetDWORD(pControlNode,"pauseatend", timeToPauseAtEnd);
+ XMLUtils::GetBoolean(pControlNode, "randomize", randomized);
+ XMLUtils::GetBoolean(pControlNode, "loop", loop);
+ XMLUtils::GetBoolean(pControlNode, "scrollout", scrollOut);
+
+ GetFloat(pControlNode, "radiowidth", radioWidth);
+ GetFloat(pControlNode, "radioheight", radioHeight);
+ GetFloat(pControlNode, "radioposx", radioPosX);
+ GetFloat(pControlNode, "radioposy", radioPosY);
+ GetFloat(pControlNode, "spinposx", radioPosX);
+ CStdString borderStr;
+ if (XMLUtils::GetString(pControlNode, "bordersize", borderStr))
+ GetRectFromString(borderStr, borderSize);
+
+ XMLUtils::GetBoolean(pControlNode, "showonepage", showOnePage);
+ XMLUtils::GetInt(pControlNode, "focusposition", focusPosition);
+ XMLUtils::GetInt(pControlNode, "scrolltime", scrollTime);
+ XMLUtils::GetInt(pControlNode, "preloaditems", preloadItems, 0, 2);
+
+ XMLUtils::GetBoolean(pControlNode, "usecontrolcoords", useControlCoords);
+ XMLUtils::GetBoolean(pControlNode, "renderfocusedlast", renderFocusedLast);
+ XMLUtils::GetBoolean(pControlNode, "resetonlabelchange", resetOnLabelChange);
+
+ XMLUtils::GetBoolean(pControlNode, "password", bPassword);
+
+ // view type
+ VIEW_TYPE viewType = VIEW_TYPE_NONE;
+ CStdString viewLabel;
+ if (strType == "panel")
+ {
+ viewType = VIEW_TYPE_ICON;
+ viewLabel = g_localizeStrings.Get(536);
+ }
+ else if (strType == "list")
+ {
+ viewType = VIEW_TYPE_LIST;
+ viewLabel = g_localizeStrings.Get(535);
+ }
+ else
+ {
+ viewType = VIEW_TYPE_WRAP;
+ viewLabel = g_localizeStrings.Get(541);
+ }
+ TiXmlElement *itemElement = pControlNode->FirstChildElement("viewtype");
+ if (itemElement && itemElement->FirstChild())
+ {
+ CStdString type = itemElement->FirstChild()->Value();
+ if (type == "list")
+ viewType = VIEW_TYPE_LIST;
+ else if (type == "icon")
+ viewType = VIEW_TYPE_ICON;
+ else if (type == "biglist")
+ viewType = VIEW_TYPE_BIG_LIST;
+ else if (type == "bigicon")
+ viewType = VIEW_TYPE_BIG_ICON;
+ else if (type == "wide")
+ viewType = VIEW_TYPE_WIDE;
+ else if (type == "bigwide")
+ viewType = VIEW_TYPE_BIG_WIDE;
+ else if (type == "wrap")
+ viewType = VIEW_TYPE_WRAP;
+ else if (type == "bigwrap")
+ viewType = VIEW_TYPE_BIG_WRAP;
+ const char *label = itemElement->Attribute("label");
+ if (label)
+ viewLabel = CGUIInfoLabel::GetLabel(FilterLabel(label));
+ }
+
+ TiXmlElement *cam = pControlNode->FirstChildElement("camera");
+ if (cam)
+ {
+ hasCamera = true;
+ g_SkinInfo.ResolveConstant(cam->Attribute("x"), camera.x);
+ g_SkinInfo.ResolveConstant(cam->Attribute("y"), camera.y);
+ }
+
+ XMLUtils::GetInt(pControlNode, "scrollspeed", scrollSpeed);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Instantiate a new control using the properties gathered above
+ //
+
+ CGUIControl *control = NULL;
+ if (strType == "group")
+ {
+ if (insideContainer)
+ {
+ control = new CGUIListGroup(parentID, id, posX, posY, width, height);
+ }
+ else
+ {
+ control = new CGUIControlGroup(
+ parentID, id, posX, posY, width, height);
+ ((CGUIControlGroup *)control)->SetDefaultControl(defaultControl, defaultAlways);
+ ((CGUIControlGroup *)control)->SetRenderFocusedLast(renderFocusedLast);
+ }
+ }
+ else if (strType == "grouplist")
+ {
+ control = new CGUIControlGroupList(
+ parentID, id, posX, posY, width, height, buttonGap, pageControl, orientation, useControlCoords, labelInfo.align);
+ ((CGUIControlGroup *)control)->SetRenderFocusedLast(renderFocusedLast);
+ }
+ else if (strType == "label")
+ {
+ const CGUIInfoLabel &content = (infoLabels.size()) ? infoLabels[0] : CGUIInfoLabel("");
+ if (insideContainer)
+ { // inside lists we use CGUIListLabel
+ control = new CGUIListLabel(parentID, id, posX, posY, width, height, labelInfo, content, bScrollLabel, scrollSpeed);
+ }
+ else
+ {
+ control = new CGUILabelControl(
+ parentID, id, posX, posY, width, height,
+ labelInfo, wrapMultiLine, bHasPath);
+ ((CGUILabelControl *)control)->SetInfo(content);
+ ((CGUILabelControl *)control)->SetWidthControl(bScrollLabel, scrollSpeed);
+ }
+ }
+ else if (strType == "edit")
+ {
+ control = new CGUIEditControl(
+ parentID, id, posX, posY, width, height, textureFocus, textureNoFocus,
+ labelInfo, strLabel);
+
+ if (bPassword)
+ ((CGUIEditControl *) control)->SetInputType(CGUIEditControl::INPUT_TYPE_PASSWORD, 0);
+ ((CGUIEditControl *) control)->SetTextChangeActions(textChangeActions);
+ }
+ else if (strType == "videowindow")
+ {
+ control = new CGUIVideoControl(
+ parentID, id, posX, posY, width, height);
+ }
+ else if (strType == "fadelabel")
+ {
+ control = new CGUIFadeLabelControl(
+ parentID, id, posX, posY, width, height,
+ labelInfo, scrollOut, scrollSpeed, timeToPauseAtEnd, resetOnLabelChange);
+
+ ((CGUIFadeLabelControl *)control)->SetInfo(infoLabels);
+ }
+ else if (strType == "rss")
+ {
+ control = new CGUIRSSControl(
+ parentID, id, posX, posY, width, height,
+ labelInfo, textColor3, labelInfo2.textColor, strRSSTags, scrollSpeed);
+
+ std::map<int, std::pair<std::vector<int>,std::vector<string> > >::iterator iter=g_settings.m_mapRssUrls.find(iUrlSet);
+ if (iter != g_settings.m_mapRssUrls.end())
+ {
+ ((CGUIRSSControl *)control)->SetUrls(iter->second.second);
+ ((CGUIRSSControl *)control)->SetIntervals(iter->second.first);
+ }
+ else
+ CLog::Log(LOGERROR,"invalid rss url set referenced in skin");
+ }
+ else if (strType == "button")
+ {
+ control = new CGUIButtonControl(
+ parentID, id, posX, posY, width, height,
+ textureFocus, textureNoFocus,
+ labelInfo);
+
+ ((CGUIButtonControl *)control)->SetLabel(strLabel);
+ ((CGUIButtonControl *)control)->SetLabel2(strLabel2);
+ ((CGUIButtonControl *)control)->SetClickActions(clickActions);
+ ((CGUIButtonControl *)control)->SetFocusActions(focusActions);
+ ((CGUIButtonControl *)control)->SetUnFocusActions(unfocusActions);
+ }
+ else if (strType == "togglebutton")
+ {
+ control = new CGUIToggleButtonControl(
+ parentID, id, posX, posY, width, height,
+ textureFocus, textureNoFocus,
+ textureAltFocus, textureAltNoFocus, labelInfo);
+
+ ((CGUIToggleButtonControl *)control)->SetLabel(strLabel);
+ ((CGUIToggleButtonControl *)control)->SetAltLabel(altLabel);
+ ((CGUIToggleButtonControl *)control)->SetClickActions(clickActions);
+ ((CGUIToggleButtonControl *)control)->SetAltClickActions(altclickActions);
+ ((CGUIToggleButtonControl *)control)->SetFocusActions(focusActions);
+ ((CGUIToggleButtonControl *)control)->SetUnFocusActions(unfocusActions);
+ ((CGUIToggleButtonControl *)control)->SetToggleSelect(iToggleSelect);
+ }
+ else if (strType == "checkmark")
+ {
+ control = new CGUICheckMarkControl(
+ parentID, id, posX, posY, width, height,
+ textureCheckMark, textureCheckMarkNF,
+ checkWidth, checkHeight, labelInfo);
+
+ ((CGUICheckMarkControl *)control)->SetLabel(strLabel);
+ }
+ else if (strType == "radiobutton")
+ {
+ control = new CGUIRadioButtonControl(
+ parentID, id, posX, posY, width, height,
+ textureFocus, textureNoFocus,
+ labelInfo,
+ textureRadioOn, textureRadioOff);
+
+ ((CGUIRadioButtonControl *)control)->SetLabel(strLabel);
+ ((CGUIRadioButtonControl *)control)->SetRadioDimensions(radioPosX, radioPosY, radioWidth, radioHeight);
+ ((CGUIRadioButtonControl *)control)->SetToggleSelect(iToggleSelect);
+ ((CGUIRadioButtonControl *)control)->SetClickActions(clickActions);
+ ((CGUIRadioButtonControl *)control)->SetFocusActions(focusActions);
+ ((CGUIRadioButtonControl *)control)->SetUnFocusActions(unfocusActions);
+ }
+ else if (strType == "multiselect")
+ {
+ CGUIInfoLabel label;
+ if (infoLabels.size())
+ label = infoLabels[0];
+ control = new CGUIMultiSelectTextControl(
+ parentID, id, posX, posY, width, height,
+ textureFocus, textureNoFocus, labelInfo, label);
+ }
+ else if (strType == "spincontrol")
+ {
+ control = new CGUISpinControl(
+ parentID, id, posX, posY, width, height,
+ textureUp, textureDown, textureUpFocus, textureDownFocus,
+ labelInfo, iType);
+
+ ((CGUISpinControl *)control)->SetReverse(bReverse);
+
+ if (iType == SPIN_CONTROL_TYPE_INT)
+ {
+ ((CGUISpinControl *)control)->SetRange(iMin, iMax);
+ }
+ else if (iType == SPIN_CONTROL_TYPE_PAGE)
+ {
+ ((CGUISpinControl *)control)->SetRange(iMin, iMax);
+ ((CGUISpinControl *)control)->SetShowRange(true);
+ ((CGUISpinControl *)control)->SetReverse(false);
+ ((CGUISpinControl *)control)->SetShowOnePage(showOnePage);
+ }
+ else if (iType == SPIN_CONTROL_TYPE_FLOAT)
+ {
+ ((CGUISpinControl *)control)->SetFloatRange(fMin, fMax);
+ ((CGUISpinControl *)control)->SetFloatInterval(fInterval);
+ }
+ }
+ else if (strType == "slider")
+ {
+ control = new CGUISliderControl(
+ parentID, id, posX, posY, width, height,
+ textureBar, textureNib, textureNibFocus, SPIN_CONTROL_TYPE_TEXT);
+
+ ((CGUISliderControl *)control)->SetInfo(singleInfo);
+ }
+ else if (strType == "sliderex")
+ {
+ labelInfo.align |= XBFONT_CENTER_Y; // always center text vertically
+ control = new CGUISettingsSliderControl(
+ parentID, id, posX, posY, width, height, sliderWidth, sliderHeight, textureFocus, textureNoFocus,
+ textureBar, textureNib, textureNibFocus, labelInfo, SPIN_CONTROL_TYPE_TEXT);
+
+ ((CGUISettingsSliderControl *)control)->SetText(strLabel);
+ ((CGUISettingsSliderControl *)control)->SetInfo(singleInfo);
+ }
+ else if (strType == "scrollbar")
+ {
+ control = new CGUIScrollBar(
+ parentID, id, posX, posY, width, height,
+ textureBackground, textureBar, textureBarFocus, textureNib, textureNibFocus, orientation, showOnePage);
+ }
+ else if (strType == "progress")
+ {
+ control = new CGUIProgressControl(
+ parentID, id, posX, posY, width, height,
+ textureBackground, textureLeft, textureMid, textureRight,
+ textureOverlay, rMin, rMax, bReveal);
+ ((CGUIProgressControl *)control)->SetInfo(singleInfo);
+ }
+ else if (strType == "image" || strType == "largeimage")
+ {
+ if (strType == "largeimage")
+ texture.useLarge = true;
+
+ // use a bordered texture if we have <bordersize> or <bordertexture> specified.
+ if (borderTexture.filename.IsEmpty() && borderStr.IsEmpty())
+ control = new CGUIImage(
+ parentID, id, posX, posY, width, height, texture);
+ else
+ control = new CGUIBorderedImage(
+ parentID, id, posX, posY, width, height, texture, borderTexture, borderSize);
+#ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY
+ if (insideContainer && textureFile.IsConstant())
+ aspect.ratio = CAspectRatio::AR_STRETCH;
+#endif
+ ((CGUIImage *)control)->SetInfo(textureFile);
+ ((CGUIImage *)control)->SetAspectRatio(aspect);
+ ((CGUIImage *)control)->SetCrossFade(fadeTime);
+ }
+ else if (strType == "multiimage")
+ {
+ control = new CGUIMultiImage(
+ parentID, id, posX, posY, width, height, texture, timePerImage, fadeTime, randomized, loop, timeToPauseAtEnd);
+ ((CGUIMultiImage *)control)->SetInfo(texturePath);
+ ((CGUIMultiImage *)control)->SetAspectRatio(aspect.ratio);
+ }
+ else if (strType == "list")
+ {
+ control = new CGUIListContainer(parentID, id, posX, posY, width, height, orientation, scrollTime, preloadItems);
+ ((CGUIListContainer *)control)->LoadLayout(pControlNode);
+ ((CGUIListContainer *)control)->LoadContent(pControlNode);
+ ((CGUIListContainer *)control)->SetType(viewType, viewLabel);
+ ((CGUIListContainer *)control)->SetPageControl(pageControl);
+ }
+ else if (strType == "wraplist")
+ {
+ control = new CGUIWrappingListContainer(parentID, id, posX, posY, width, height, orientation, scrollTime, preloadItems, focusPosition);
+ ((CGUIWrappingListContainer *)control)->LoadLayout(pControlNode);
+ ((CGUIWrappingListContainer *)control)->LoadContent(pControlNode);
+ ((CGUIWrappingListContainer *)control)->SetType(viewType, viewLabel);
+ ((CGUIWrappingListContainer *)control)->SetPageControl(pageControl);
+ }
+ else if (strType == "fixedlist")
+ {
+ control = new CGUIFixedListContainer(parentID, id, posX, posY, width, height, orientation, scrollTime, preloadItems, focusPosition);
+ ((CGUIFixedListContainer *)control)->LoadLayout(pControlNode);
+ ((CGUIFixedListContainer *)control)->LoadContent(pControlNode);
+ ((CGUIFixedListContainer *)control)->SetType(viewType, viewLabel);
+ ((CGUIFixedListContainer *)control)->SetPageControl(pageControl);
+ }
+ else if (strType == "panel")
+ {
+ control = new CGUIPanelContainer(parentID, id, posX, posY, width, height, orientation, scrollTime, preloadItems);
+ ((CGUIPanelContainer *)control)->LoadLayout(pControlNode);
+ ((CGUIPanelContainer *)control)->LoadContent(pControlNode);
+ ((CGUIPanelContainer *)control)->SetType(viewType, viewLabel);
+ ((CGUIPanelContainer *)control)->SetPageControl(pageControl);
+ }
+ else if (strType == "textbox")
+ {
+ control = new CGUITextBox(
+ parentID, id, posX, posY, width, height,
+ labelInfo, scrollTime);
+
+ ((CGUITextBox *)control)->SetPageControl(pageControl);
+ if (infoLabels.size())
+ ((CGUITextBox *)control)->SetInfo(infoLabels[0]);
+ ((CGUITextBox *)control)->SetAutoScrolling(pControlNode);
+ }
+ else if (strType == "selectbutton")
+ {
+ control = new CGUISelectButtonControl(
+ parentID, id, posX, posY,
+ width, height, textureFocus, textureNoFocus,
+ labelInfo,
+ textureBackground, textureLeft, textureLeftFocus, textureRight, textureRightFocus);
+
+ ((CGUISelectButtonControl *)control)->SetLabel(strLabel);
+ }
+ else if (strType == "mover")
+ {
+ control = new CGUIMoverControl(
+ parentID, id, posX, posY, width, height,
+ textureFocus, textureNoFocus);
+ }
+ else if (strType == "resize")
+ {
+ control = new CGUIResizeControl(
+ parentID, id, posX, posY, width, height,
+ textureFocus, textureNoFocus);
+ }
+ else if (strType == "buttonscroller")
+ {
+ control = new CGUIButtonScroller(
+ parentID, id, posX, posY, width, height, buttonGap, iNumSlots, iDefaultSlot,
+ iMovementRange, bHorizontal, iAlpha, bWrapAround, bSmoothScrolling,
+ textureFocus, textureNoFocus, labelInfo);
+ ((CGUIButtonScroller *)control)->LoadButtons(pControlNode);
+ }
+ else if (strType == "spincontrolex")
+ {
+ control = new CGUISpinControlEx(
+ parentID, id, posX, posY, width, height, spinWidth, spinHeight,
+ labelInfo, textureFocus, textureNoFocus, textureUp, textureDown, textureUpFocus, textureDownFocus,
+ labelInfo, iType);
+
+ ((CGUISpinControlEx *)control)->SetSpinPosition(radioPosX);
+ ((CGUISpinControlEx *)control)->SetText(strLabel);
+ ((CGUISpinControlEx *)control)->SetReverse(bReverse);
+ }
+ else if (strType == "visualisation" || strType == "karvisualisation")
+ {
+ control = new CGUIVisualisationControl(parentID, id, posX, posY, width, height);
+ }
+
+ // things that apply to all controls
+ if (control)
+ {
+ control->SetHitRect(hitRect);
+ control->SetVisibleCondition(iVisibleCondition, allowHiddenFocus);
+ control->SetEnableCondition(enableCondition);
+ control->SetAnimations(animations);
+ control->SetColorDiffuse(colorDiffuse);
+ control->SetNavigation(up, down, left, right);
+ control->SetTabNavigation(next,prev);
+ control->SetNavigationActions(upActions, downActions, leftActions, rightActions);
+ control->SetPulseOnSelect(bPulse);
+ if (hasCamera)
+ control->SetCamera(camera);
+ }
+ return control;
+}
+
+void CGUIControlFactory::ScaleElement(TiXmlElement *element, RESOLUTION fileRes, RESOLUTION destRes)
+{
+ if (element->FirstChild())
+ {
+ const char *value = element->FirstChild()->Value();
+ if (value)
+ {
+ float v = (float)atof(value);
+ CStdString name = element->Value();
+ if (name == "posx" ||
+ name == "width" ||
+ name == "gfxthumbwidth" ||
+ name == "gfxthumbspacex" ||
+ name == "textoffsetx" ||
+ name == "textxoff" ||
+ name == "textxoff2" ||
+ name == "textwidth" ||
+ name == "spinwidth" ||
+ name == "spinposx" ||
+ name == "markwidth" ||
+ name == "sliderwidth" ||
+ name == "itemwidth" ||
+ name == "texturewidth" ||
+ name == "thumbwidth" ||
+ name == "thumbposx" ||
+ name == "thumbwidthbig" ||
+ name == "thumbposxbig" ||
+ name == "texturewidthbig" ||
+ name == "itemwidthbig" ||
+ name == "radiowidth" ||
+ name == "radioposx")
+ {
+ // scale
+ v *= (float)g_settings.m_ResInfo[destRes].iWidth / g_settings.m_ResInfo[fileRes].iWidth;
+ CStdString floatValue;
+ floatValue.Format("%f", v);
+ element->FirstChild()->SetValue(floatValue);
+ }
+ else if (name == "posy" ||
+ name == "height" ||
+ name == "textspacey" ||
+ name == "gfxthumbheight" ||
+ name == "gfxthumbspacey" ||
+ name == "textoffsety" ||
+ name == "textyoff" ||
+ name == "textyoff2" ||
+ name == "spinheight" ||
+ name == "spinposy" ||
+ name == "markheight" ||
+ name == "sliderheight" ||
+ name == "spacebetweenitems" ||
+ name == "textureheight" ||
+ name == "thumbheight" ||
+ name == "thumbposy" ||
+ name == "thumbheightbig" ||
+ name == "thumbposybig" ||
+ name == "textureheightbig" ||
+ name == "itemheightbig" ||
+ name == "buttongap" || // should really depend on orientation
+ name == "radioheight" ||
+ name == "radioposy")
+ {
+ // scale
+ v *= (float)g_settings.m_ResInfo[destRes].iHeight / g_settings.m_ResInfo[fileRes].iHeight;
+ CStdString floatValue;
+ floatValue.Format("%f", v);
+ element->FirstChild()->SetValue(floatValue);
+ }
+ }
+ }
+}
diff --git a/guilib/GUIControlFactory.h b/guilib/GUIControlFactory.h
new file mode 100644
index 0000000000..76db5d3f2f
--- /dev/null
+++ b/guilib/GUIControlFactory.h
@@ -0,0 +1,77 @@
+/*!
+\file GuiControlFactory.h
+\brief
+*/
+
+#ifndef GUI_CONTROL_FACTORY_H
+#define GIU_CONTROL_FACTORY_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+
+class CTextureInfo; // forward
+class CAspectRatio;
+class CGUIInfoLabel;
+class TiXmlNode;
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIControlFactory
+{
+public:
+ CGUIControlFactory(void);
+ virtual ~CGUIControlFactory(void);
+ static CStdString GetType(const TiXmlElement *pControlNode);
+ CGUIControl* Create(int parentID, const FRECT &rect, TiXmlElement* pControlNode, bool insideContainer = false);
+ void ScaleElement(TiXmlElement *element, RESOLUTION fileRes, RESOLUTION destRes);
+ static bool GetFloat(const TiXmlNode* pRootNode, const char* strTag, float& value);
+ static bool GetDWORD(const TiXmlNode* pRootNode, const char* strTag, DWORD& value);
+ static bool GetAspectRatio(const TiXmlNode* pRootNode, const char* strTag, CAspectRatio &aspectRatio);
+ static bool GetInfoTexture(const TiXmlNode* pRootNode, const char* strTag, CTextureInfo &image, CGUIInfoLabel &info);
+ static bool GetTexture(const TiXmlNode* pRootNode, const char* strTag, CTextureInfo &image);
+ static bool GetAlignment(const TiXmlNode* pRootNode, const char* strTag, uint32_t& dwAlignment);
+ static bool GetAlignmentY(const TiXmlNode* pRootNode, const char* strTag, uint32_t& dwAlignment);
+ static bool GetAnimations(const TiXmlNode *control, const FRECT &rect, std::vector<CAnimation> &animation);
+ static void GetInfoLabel(const TiXmlNode *pControlNode, const CStdString &labelTag, CGUIInfoLabel &infoLabel);
+ static void GetInfoLabels(const TiXmlNode *pControlNode, const CStdString &labelTag, std::vector<CGUIInfoLabel> &infoLabels);
+ static bool GetColor(const TiXmlNode* pRootNode, const char* strTag, color_t &value);
+ static bool GetInfoColor(const TiXmlNode* pRootNode, const char* strTag, CGUIInfoColor &value);
+ static CStdString FilterLabel(const CStdString &label);
+ static bool GetConditionalVisibility(const TiXmlNode* control, int &condition);
+ static bool GetMultipleString(const TiXmlNode* pRootNode, const char* strTag, std::vector<CGUIActionDescriptor>& vecStringValue);
+ static void GetRectFromString(const CStdString &string, FRECT &rect);
+ static bool GetAction(const TiXmlElement* pElement, CGUIActionDescriptor &action);
+private:
+ bool GetNavigation(const TiXmlElement *node, const char *tag, int &direction, std::vector<CGUIActionDescriptor> &actions);
+ bool GetCondition(const TiXmlNode *control, const char *tag, int &condition);
+ static bool GetConditionalVisibility(const TiXmlNode* control, int &condition, CGUIInfoBool &allowHiddenFocus);
+ bool GetString(const TiXmlNode* pRootNode, const char* strTag, CStdString& strString);
+ bool GetFloatRange(const TiXmlNode* pRootNode, const char* strTag, float& iMinValue, float& iMaxValue, float& iIntervalValue);
+ bool GetIntRange(const TiXmlNode* pRootNode, const char* strTag, int& iMinValue, int& iMaxValue, int& iIntervalValue);
+ bool GetHitRect(const TiXmlNode* pRootNode, CRect &rect);
+};
+#endif
diff --git a/guilib/GUIControlGroup.cpp b/guilib/GUIControlGroup.cpp
new file mode 100644
index 0000000000..1b377c1e4d
--- /dev/null
+++ b/guilib/GUIControlGroup.cpp
@@ -0,0 +1,631 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControlGroup.h"
+#include "GUIControlProfiler.h"
+
+using namespace std;
+
+CGUIControlGroup::CGUIControlGroup()
+{
+ m_defaultControl = 0;
+ m_defaultAlways = false;
+ m_focusedControl = 0;
+ m_renderTime = 0;
+ m_renderFocusedLast = false;
+ ControlType = GUICONTROL_GROUP;
+}
+
+CGUIControlGroup::CGUIControlGroup(int parentID, int controlID, float posX, float posY, float width, float height)
+: CGUIControl(parentID, controlID, posX, posY, width, height)
+{
+ m_defaultControl = 0;
+ m_defaultAlways = false;
+ m_focusedControl = 0;
+ m_renderTime = 0;
+ m_renderFocusedLast = false;
+ ControlType = GUICONTROL_GROUP;
+}
+
+CGUIControlGroup::CGUIControlGroup(const CGUIControlGroup &from)
+: CGUIControl(from)
+{
+ m_defaultControl = from.m_defaultControl;
+ m_defaultAlways = from.m_defaultAlways;
+ m_renderFocusedLast = from.m_renderFocusedLast;
+
+ // run through and add our controls
+ for (ciControls it = from.m_children.begin(); it != from.m_children.end(); ++it)
+ AddControl((*it)->Clone());
+
+ // defaults
+ m_focusedControl = 0;
+ m_renderTime = 0;
+ ControlType = GUICONTROL_GROUP;
+}
+
+CGUIControlGroup::~CGUIControlGroup(void)
+{
+ ClearAll();
+}
+
+void CGUIControlGroup::AllocResources()
+{
+ CGUIControl::AllocResources();
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *control = *it;
+ if (!control->IsDynamicallyAllocated())
+ control->AllocResources();
+ }
+}
+
+void CGUIControlGroup::FreeResources()
+{
+ CGUIControl::FreeResources();
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *control = *it;
+ control->FreeResources();
+ }
+}
+
+void CGUIControlGroup::DynamicResourceAlloc(bool bOnOff)
+{
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *control = *it;
+ control->DynamicResourceAlloc(bOnOff);
+ }
+}
+
+void CGUIControlGroup::Render()
+{
+ g_graphicsContext.SetOrigin(m_posX, m_posY);
+ CGUIControl *focusedControl = NULL;
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *control = *it;
+ GUIPROFILER_VISIBILITY_BEGIN(control);
+ control->UpdateVisibility();
+ GUIPROFILER_VISIBILITY_END(control);
+ if (m_renderFocusedLast && control->HasFocus())
+ focusedControl = control;
+ else
+ control->DoRender(m_renderTime);
+ }
+ if (focusedControl)
+ focusedControl->DoRender(m_renderTime);
+ CGUIControl::Render();
+ g_graphicsContext.RestoreOrigin();
+}
+
+bool CGUIControlGroup::OnAction(const CAction &action)
+{
+ ASSERT(false); // unimplemented
+ return false;
+}
+
+bool CGUIControlGroup::HasFocus() const
+{
+ for (ciControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *control = *it;
+ if (control->HasFocus())
+ return true;
+ }
+ return false;
+}
+
+bool CGUIControlGroup::OnMessage(CGUIMessage& message)
+{
+ switch (message.GetMessage() )
+ {
+ case GUI_MSG_ITEM_SELECT:
+ {
+ if (message.GetControlId() == GetID())
+ {
+ m_focusedControl = message.GetParam1();
+ return true;
+ }
+ break;
+ }
+ case GUI_MSG_ITEM_SELECTED:
+ {
+ if (message.GetControlId() == GetID())
+ {
+ message.SetParam1(m_focusedControl);
+ return true;
+ }
+ break;
+ }
+ case GUI_MSG_FOCUSED:
+ { // a control has been focused
+ m_focusedControl = message.GetControlId();
+ SetFocus(true);
+ // tell our parent thatwe have focus
+ if (m_parentControl)
+ m_parentControl->OnMessage(message);
+ return true;
+ }
+ case GUI_MSG_SETFOCUS:
+ {
+ // first try our last focused control...
+ if (!m_defaultAlways && m_focusedControl)
+ {
+ CGUIControl *control = GetFirstFocusableControl(m_focusedControl);
+ if (control)
+ {
+ CGUIMessage msg(GUI_MSG_SETFOCUS, GetParentID(), control->GetID());
+ return control->OnMessage(msg);
+ }
+ }
+ // ok, no previously focused control, try the default control first
+ if (m_defaultControl)
+ {
+ CGUIControl *control = GetFirstFocusableControl(m_defaultControl);
+ if (control)
+ {
+ CGUIMessage msg(GUI_MSG_SETFOCUS, GetParentID(), control->GetID());
+ return control->OnMessage(msg);
+ }
+ }
+ // no success with the default control, so just find one to focus
+ CGUIControl *control = GetFirstFocusableControl(0);
+ if (control)
+ {
+ CGUIMessage msg(GUI_MSG_SETFOCUS, GetParentID(), control->GetID());
+ return control->OnMessage(msg);
+ }
+ // unsuccessful
+ return false;
+ break;
+ }
+ case GUI_MSG_LOSTFOCUS:
+ {
+ // set all subcontrols unfocused
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ (*it)->SetFocus(false);
+ if (!HasID(message.GetParam1()))
+ { // we don't have the new id, so unfocus
+ SetFocus(false);
+ if (m_parentControl)
+ m_parentControl->OnMessage(message);
+ }
+ return true;
+ }
+ break;
+ case GUI_MSG_PAGE_CHANGE:
+ case GUI_MSG_REFRESH_THUMBS:
+ case GUI_MSG_REFRESH_LIST:
+ { // send to all child controls (make sure the target is the control id)
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIMessage msg(message.GetMessage(), message.GetSenderId(), (*it)->GetID(), message.GetParam1());
+ (*it)->OnMessage(msg);
+ }
+ return true;
+ }
+ break;
+ }
+ bool handled(false);
+ //not intented for any specific control, send to all childs and our base handler.
+ if (message.GetControlId() == 0)
+ {
+ for (iControls it = m_children.begin();it != m_children.end(); ++it)
+ {
+ CGUIControl* control = *it;
+ handled |= control->OnMessage(message);
+ }
+ return CGUIControl::OnMessage(message) || handled;
+ }
+ // if it's intended for us, then so be it
+ if (message.GetControlId() == GetID())
+ return CGUIControl::OnMessage(message);
+
+ return SendControlMessage(message);
+}
+
+bool CGUIControlGroup::SendControlMessage(CGUIMessage &message)
+{
+ // see if a child matches, and send to the child control if so
+ for (iControls it = m_children.begin();it != m_children.end(); ++it)
+ {
+ CGUIControl* control = *it;
+ if (control->HasVisibleID(message.GetControlId()))
+ {
+ if (control->OnMessage(message))
+ return true;
+ }
+ }
+ // Unhandled - send to all matching invisible controls as well
+ bool handled(false);
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl* control = *it;
+ if (control->HasID(message.GetControlId()))
+ {
+ if (control->OnMessage(message))
+ handled = true;
+ }
+ }
+ return handled;
+}
+
+bool CGUIControlGroup::CanFocus() const
+{
+ if (!CGUIControl::CanFocus()) return false;
+ // see if we have any children that can be focused
+ for (ciControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ if ((*it)->CanFocus())
+ return true;
+ }
+ return false;
+}
+
+void CGUIControlGroup::DoRender(DWORD currentTime)
+{
+ m_renderTime = currentTime;
+ CGUIControl::DoRender(currentTime);
+}
+
+void CGUIControlGroup::SetInitialVisibility()
+{
+ CGUIControl::SetInitialVisibility();
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ (*it)->SetInitialVisibility();
+}
+
+void CGUIControlGroup::QueueAnimation(ANIMATION_TYPE animType)
+{
+ CGUIControl::QueueAnimation(animType);
+ // send window level animations to our children as well
+ if (animType == ANIM_TYPE_WINDOW_OPEN || animType == ANIM_TYPE_WINDOW_CLOSE)
+ {
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ (*it)->QueueAnimation(animType);
+ }
+}
+
+void CGUIControlGroup::ResetAnimation(ANIMATION_TYPE animType)
+{
+ CGUIControl::ResetAnimation(animType);
+ // send window level animations to our children as well
+ if (animType == ANIM_TYPE_WINDOW_OPEN || animType == ANIM_TYPE_WINDOW_CLOSE)
+ {
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ (*it)->ResetAnimation(animType);
+ }
+}
+
+void CGUIControlGroup::ResetAnimations()
+{ // resets all animations, regardless of condition
+ CGUIControl::ResetAnimations();
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ (*it)->ResetAnimations();
+}
+
+bool CGUIControlGroup::IsAnimating(ANIMATION_TYPE animType)
+{
+ if (CGUIControl::IsAnimating(animType))
+ return true;
+
+ if (IsVisible())
+ {
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ if ((*it)->IsAnimating(animType))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CGUIControlGroup::HasAnimation(ANIMATION_TYPE animType)
+{
+ if (CGUIControl::HasAnimation(animType))
+ return true;
+
+ if (IsVisible())
+ {
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ if ((*it)->HasAnimation(animType))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CGUIControlGroup::HitTest(const CPoint &point) const
+{
+ for (ciControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *child = *it;
+ if (child->HitTest(point - CPoint(m_posX, m_posX)))
+ return true;
+ }
+ return false;
+}
+
+bool CGUIControlGroup::CanFocusFromPoint(const CPoint &point, CGUIControl **control, CPoint &controlPoint) const
+{
+ if (!CGUIControl::CanFocus()) return false;
+ CPoint controlCoords(point);
+ m_transform.InverseTransformPosition(controlCoords.x, controlCoords.y);
+ for (crControls it = m_children.rbegin(); it != m_children.rend(); ++it)
+ {
+ CGUIControl *child = *it;
+ if (child->CanFocusFromPoint(controlCoords - CPoint(m_posX, m_posY), control, controlPoint))
+ return true;
+ }
+ *control = NULL;
+ return false;
+}
+
+void CGUIControlGroup::UnfocusFromPoint(const CPoint &point)
+{
+ CPoint controlCoords(point);
+ m_transform.InverseTransformPosition(controlCoords.x, controlCoords.y);
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *child = *it;
+ child->UnfocusFromPoint(controlCoords - CPoint(m_posX, m_posY));
+ }
+ CGUIControl::UnfocusFromPoint(point);
+}
+
+bool CGUIControlGroup::HasID(int id) const
+{
+ if (CGUIControl::HasID(id)) return true;
+ for (ciControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *child = *it;
+ if (child->HasID(id))
+ return true;
+ }
+ return false;
+}
+
+bool CGUIControlGroup::HasVisibleID(int id) const
+{
+ // call base class first as the group may be the requested control
+ if (CGUIControl::HasVisibleID(id)) return true;
+ // if the group isn't visible, then none of it's children can be
+ if (!IsVisible()) return false;
+ for (ciControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *child = *it;
+ if (child->HasVisibleID(id))
+ return true;
+ }
+ return false;
+}
+
+const CGUIControl* CGUIControlGroup::GetControl(int iControl) const
+{
+ CGUIControl *pPotential = NULL;
+ LookupMap::const_iterator first = m_lookup.find(iControl);
+ if (first != m_lookup.end())
+ {
+ LookupMap::const_iterator last = m_lookup.upper_bound(iControl);
+ for (LookupMap::const_iterator i = first; i != last; i++)
+ {
+ CGUIControl *control = i->second;
+ if (control->IsVisible())
+ return control;
+ else if (!pPotential)
+ pPotential = control;
+ }
+ }
+ return pPotential;
+}
+
+int CGUIControlGroup::GetFocusedControlID() const
+{
+ if (m_focusedControl) return m_focusedControl;
+ CGUIControl *control = GetFocusedControl();
+ if (control) return control->GetID();
+ return 0;
+}
+
+CGUIControl *CGUIControlGroup::GetFocusedControl() const
+{
+ for (ciControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ const CGUIControl* control = *it;
+ if (control->HasFocus())
+ {
+ if (control->IsGroup())
+ {
+ CGUIControlGroup *group = (CGUIControlGroup *)control;
+ return group->GetFocusedControl();
+ }
+ return (CGUIControl *)control;
+ }
+ }
+ return NULL;
+}
+
+// in the case of id == 0, we don't match id
+CGUIControl *CGUIControlGroup::GetFirstFocusableControl(int id)
+{
+ if (!CanFocus()) return NULL;
+ if (id && id == (int) GetID()) return this; // we're focusable and they want us
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl* pControl = *it;
+ if (pControl->IsGroup())
+ {
+ CGUIControlGroup *group = (CGUIControlGroup *)pControl;
+ CGUIControl *control = group->GetFirstFocusableControl(id);
+ if (control) return control;
+ }
+ if ((!id || (int) pControl->GetID() == id) && pControl->CanFocus())
+ return pControl;
+ }
+ return NULL;
+}
+
+void CGUIControlGroup::AddControl(CGUIControl *control, int position /* = -1*/)
+{
+ if (!control) return;
+ if (position < 0 || position > (int)m_children.size())
+ position = (int)m_children.size();
+ m_children.insert(m_children.begin() + position, control);
+ control->SetParentControl(this);
+ AddLookup(control);
+}
+
+void CGUIControlGroup::AddLookup(CGUIControl *control)
+{
+ if (control->IsGroup())
+ { // first add all the subitems of this group (if they exist)
+ const LookupMap map = ((CGUIControlGroup *)control)->GetLookup();
+ for (LookupMap::const_iterator i = map.begin(); i != map.end(); i++)
+ m_lookup.insert(m_lookup.upper_bound(i->first), make_pair(i->first, i->second));
+ }
+ if (control->GetID())
+ m_lookup.insert(m_lookup.upper_bound(control->GetID()), make_pair(control->GetID(), control));
+ // ensure that our size is what it should be
+ if (m_parentControl)
+ ((CGUIControlGroup *)m_parentControl)->AddLookup(control);
+}
+
+void CGUIControlGroup::RemoveLookup(CGUIControl *control)
+{
+ if (control->IsGroup())
+ { // remove the group's lookup
+ const LookupMap &map = ((CGUIControlGroup *)control)->GetLookup();
+ for (LookupMap::const_iterator i = map.begin(); i != map.end(); i++)
+ { // remove this control
+ for (LookupMap::iterator it = m_lookup.begin(); it != m_lookup.end(); it++)
+ {
+ if (i->second == it->second)
+ {
+ m_lookup.erase(it);
+ break;
+ }
+ }
+ }
+ }
+ // remove the actual control
+ if (control->GetID())
+ {
+ for (LookupMap::iterator it = m_lookup.begin(); it != m_lookup.end(); it++)
+ {
+ if (control == it->second)
+ {
+ m_lookup.erase(it);
+ break;
+ }
+ }
+ }
+ if (m_parentControl)
+ ((CGUIControlGroup *)m_parentControl)->RemoveLookup(control);
+}
+
+bool CGUIControlGroup::InsertControl(CGUIControl *control, const CGUIControl *insertPoint)
+{
+ // find our position
+ for (unsigned int i = 0; i < m_children.size(); i++)
+ {
+ CGUIControl *child = m_children[i];
+ if (child->IsGroup() && ((CGUIControlGroup *)child)->InsertControl(control, insertPoint))
+ return true;
+ else if (child == insertPoint)
+ {
+ AddControl(control, i);
+ return true;
+ }
+ }
+ return false;
+}
+
+void CGUIControlGroup::SaveStates(vector<CControlState> &states)
+{
+ // save our state, and that of our children
+ states.push_back(CControlState(GetID(), m_focusedControl));
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ (*it)->SaveStates(states);
+}
+
+// Note: This routine doesn't delete the control. It just removes it from the control list
+bool CGUIControlGroup::RemoveControl(const CGUIControl *control)
+{
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *child = *it;
+ if (child->IsGroup() && ((CGUIControlGroup *)child)->RemoveControl(control))
+ return true;
+ if (control == child)
+ {
+ m_children.erase(it);
+ RemoveLookup(child);
+ return true;
+ }
+ }
+ return false;
+}
+
+void CGUIControlGroup::ClearAll()
+{
+ // first remove from the lookup table
+ if (m_parentControl)
+ {
+ for (iControls it = m_children.begin(); it != m_children.end(); it++)
+ ((CGUIControlGroup *)m_parentControl)->RemoveLookup(*it);
+ }
+ // and delete all our children
+ for (iControls it = m_children.begin(); it != m_children.end(); it++)
+ {
+ CGUIControl *control = *it;
+ delete control;
+ }
+ m_children.clear();
+ m_lookup.clear();
+}
+
+void CGUIControlGroup::GetContainers(vector<CGUIControl *> &containers) const
+{
+ for (ciControls it = m_children.begin();it != m_children.end(); ++it)
+ {
+ if ((*it)->IsContainer())
+ containers.push_back(*it);
+ else if ((*it)->IsGroup())
+ ((CGUIControlGroup *)(*it))->GetContainers(containers);
+ }
+}
+
+void CGUIControlGroup::SetInvalid()
+{
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ (*it)->SetInvalid();
+}
+
+#ifdef _DEBUG
+void CGUIControlGroup::DumpTextureUse()
+{
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ (*it)->DumpTextureUse();
+}
+#endif
diff --git a/guilib/GUIControlGroup.h b/guilib/GUIControlGroup.h
new file mode 100644
index 0000000000..914a9f84ce
--- /dev/null
+++ b/guilib/GUIControlGroup.h
@@ -0,0 +1,113 @@
+/*!
+\file GUIControlGroup.h
+\brief
+*/
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+
+/*!
+ \ingroup controls
+ \brief group of controls, useful for remembering last control + animating/hiding together
+ */
+class CGUIControlGroup : public CGUIControl
+{
+public:
+ CGUIControlGroup();
+ CGUIControlGroup(int parentID, int controlID, float posX, float posY, float width, float height);
+ CGUIControlGroup(const CGUIControlGroup &from);
+ virtual ~CGUIControlGroup(void);
+ virtual CGUIControlGroup *Clone() const { return new CGUIControlGroup(*this); };
+
+ virtual void Render();
+ virtual bool OnAction(const CAction &action);
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual bool SendControlMessage(CGUIMessage& message);
+ virtual bool HasFocus() const;
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual bool CanFocus() const;
+
+ virtual bool HitTest(const CPoint &point) const;
+ virtual bool CanFocusFromPoint(const CPoint &point, CGUIControl **control, CPoint &controlPoint) const;
+ virtual void UnfocusFromPoint(const CPoint &point);
+
+ virtual void SetInitialVisibility();
+
+ virtual void DoRender(DWORD currentTime);
+ virtual bool IsAnimating(ANIMATION_TYPE anim);
+ virtual bool HasAnimation(ANIMATION_TYPE anim);
+ virtual void QueueAnimation(ANIMATION_TYPE anim);
+ virtual void ResetAnimation(ANIMATION_TYPE anim);
+ virtual void ResetAnimations();
+
+ virtual bool HasID(int id) const;
+ virtual bool HasVisibleID(int id) const;
+ virtual void SetInvalid();
+
+ int GetFocusedControlID() const;
+ CGUIControl *GetFocusedControl() const;
+ const CGUIControl *GetControl(int id) const;
+ virtual CGUIControl *GetFirstFocusableControl(int id);
+ void GetContainers(std::vector<CGUIControl *> &containers) const;
+
+ virtual void AddControl(CGUIControl *control, int position = -1);
+ bool InsertControl(CGUIControl *control, const CGUIControl *insertPoint);
+ virtual bool RemoveControl(const CGUIControl *control);
+ virtual void ClearAll();
+ void SetDefaultControl(int id, bool always) { m_defaultControl = id; m_defaultAlways = always; };
+ void SetRenderFocusedLast(bool renderLast) { m_renderFocusedLast = renderLast; };
+
+ virtual void SaveStates(std::vector<CControlState> &states);
+
+ virtual bool IsGroup() const { return true; };
+
+#ifdef _DEBUG
+ virtual void DumpTextureUse();
+#endif
+protected:
+ // sub controls
+ std::vector<CGUIControl *> m_children;
+ typedef std::vector<CGUIControl *>::iterator iControls;
+ typedef std::vector<CGUIControl *>::const_iterator ciControls;
+ typedef std::vector<CGUIControl *>::const_reverse_iterator crControls;
+
+ // fast lookup by id
+ typedef std::multimap<int, CGUIControl *> LookupMap;
+ void AddLookup(CGUIControl *control);
+ void RemoveLookup(CGUIControl *control);
+ const LookupMap &GetLookup() { return m_lookup; };
+ LookupMap m_lookup;
+
+ int m_defaultControl;
+ bool m_defaultAlways;
+ int m_focusedControl;
+ bool m_renderFocusedLast;
+
+ // render time
+ DWORD m_renderTime;
+};
+
diff --git a/guilib/GUIControlGroupList.cpp b/guilib/GUIControlGroupList.cpp
new file mode 100644
index 0000000000..02c093f6ac
--- /dev/null
+++ b/guilib/GUIControlGroupList.cpp
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControlGroupList.h"
+#include "utils/GUIInfoManager.h"
+#include "GUIControlProfiler.h"
+
+#define TIME_TO_SCROLL 200;
+
+CGUIControlGroupList::CGUIControlGroupList(int parentID, int controlID, float posX, float posY, float width, float height, float itemGap, int pageControl, ORIENTATION orientation, bool useControlPositions, uint32_t alignment)
+: CGUIControlGroup(parentID, controlID, posX, posY, width, height)
+{
+ m_itemGap = itemGap;
+ m_pageControl = pageControl;
+ m_offset = 0;
+ m_totalSize = 10;
+ m_orientation = orientation;
+ m_alignment = alignment;
+ m_scrollOffset = 0;
+ m_scrollSpeed = 0;
+ m_scrollTime = 0;
+ m_renderTime = 0;
+ m_useControlPositions = useControlPositions;
+ ControlType = GUICONTROL_GROUPLIST;
+}
+
+CGUIControlGroupList::~CGUIControlGroupList(void)
+{
+}
+
+void CGUIControlGroupList::Render()
+{
+ if (m_scrollSpeed != 0)
+ {
+ m_offset += m_scrollSpeed * (m_renderTime - m_scrollTime);
+ if ((m_scrollSpeed < 0 && m_offset < m_scrollOffset) ||
+ (m_scrollSpeed > 0 && m_offset > m_scrollOffset))
+ {
+ m_offset = m_scrollOffset;
+ m_scrollSpeed = 0;
+ }
+ }
+ m_scrollTime = m_renderTime;
+
+ // first we update visibility of all our items, to ensure our size and
+ // alignment computations are correct.
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *control = *it;
+ GUIPROFILER_VISIBILITY_BEGIN(control);
+ control->UpdateVisibility();
+ GUIPROFILER_VISIBILITY_END(control);
+ }
+
+ ValidateOffset();
+ if (m_pageControl)
+ {
+ CGUIMessage message(GUI_MSG_LABEL_RESET, GetParentID(), m_pageControl, (int)m_height, (int)m_totalSize);
+ SendWindowMessage(message);
+ CGUIMessage message2(GUI_MSG_ITEM_SELECT, GetParentID(), m_pageControl, (int)m_offset);
+ SendWindowMessage(message2);
+ }
+ // we run through the controls, rendering as we go
+ bool render(g_graphicsContext.SetClipRegion(m_posX, m_posY, m_width, m_height));
+ float pos = GetAlignOffset();
+ float focusedPos = 0;
+ CGUIControl *focusedControl = NULL;
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ // note we render all controls, even if they're offscreen, as then they'll be updated
+ // with respect to animations
+ CGUIControl *control = *it;
+ if (m_renderFocusedLast && control->HasFocus())
+ {
+ focusedControl = control;
+ focusedPos = pos;
+ }
+ else
+ {
+ if (m_orientation == VERTICAL)
+ g_graphicsContext.SetOrigin(m_posX, m_posY + pos - m_offset);
+ else
+ g_graphicsContext.SetOrigin(m_posX + pos - m_offset, m_posY);
+ control->DoRender(m_renderTime);
+ }
+ if (control->IsVisible())
+ pos += Size(control) + m_itemGap;
+ g_graphicsContext.RestoreOrigin();
+ }
+ if (focusedControl)
+ {
+ if (m_orientation == VERTICAL)
+ g_graphicsContext.SetOrigin(m_posX, m_posY + focusedPos - m_offset);
+ else
+ g_graphicsContext.SetOrigin(m_posX + focusedPos - m_offset, m_posY);
+ focusedControl->DoRender(m_renderTime);
+ }
+ if (render) g_graphicsContext.RestoreClipRegion();
+ CGUIControl::Render();
+}
+
+bool CGUIControlGroupList::OnMessage(CGUIMessage& message)
+{
+ switch (message.GetMessage() )
+ {
+ case GUI_MSG_FOCUSED:
+ { // a control has been focused
+ // scroll if we need to and update our page control
+ ValidateOffset();
+ float offset = 0;
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *control = *it;
+ if (!control->IsVisible())
+ continue;
+ if (control->HasID(message.GetControlId()))
+ {
+ // find out whether this is the first or last control
+ if (IsFirstFocusableControl(control))
+ ScrollTo(0);
+ else if (IsLastFocusableControl(control))
+ ScrollTo(m_totalSize - Size());
+ else if (offset < m_offset)
+ ScrollTo(offset);
+ else if (offset + Size(control) > m_offset + Size())
+ ScrollTo(offset + Size(control) - Size());
+ break;
+ }
+ offset += Size(control) + m_itemGap;
+ }
+ }
+ break;
+ case GUI_MSG_SETFOCUS:
+ {
+ // we've been asked to focus. We focus the last control if it's on this page,
+ // else we'll focus the first focusable control from our offset (after verifying it)
+ ValidateOffset();
+ // now check the focusControl's offset
+ float offset = 0;
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *control = *it;
+ if (!control->IsVisible())
+ continue;
+ if (control->HasID(m_focusedControl))
+ {
+ if (offset >= m_offset && offset + Size(control) <= m_offset + Size())
+ return CGUIControlGroup::OnMessage(message);
+ break;
+ }
+ offset += Size(control) + m_itemGap;
+ }
+ // find the first control on this page
+ offset = 0;
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *control = *it;
+ if (!control->IsVisible())
+ continue;
+ if (control->CanFocus() && offset >= m_offset && offset + Size(control) <= m_offset + Size())
+ {
+ m_focusedControl = control->GetID();
+ break;
+ }
+ offset += Size(control) + m_itemGap;
+ }
+ }
+ break;
+ case GUI_MSG_PAGE_CHANGE:
+ {
+ if (message.GetSenderId() == m_pageControl)
+ { // it's from our page control
+ ScrollTo((float)message.GetParam1());
+ return true;
+ }
+ }
+ break;
+ }
+ return CGUIControlGroup::OnMessage(message);
+}
+
+void CGUIControlGroupList::ValidateOffset()
+{
+ // calculate how many items we have on this page
+ m_totalSize = 0;
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *control = *it;
+ if (!control->IsVisible()) continue;
+ m_totalSize += Size(control) + m_itemGap;
+ }
+ if (m_totalSize > 0) m_totalSize -= m_itemGap;
+ // check our m_offset range
+ if (m_offset > m_totalSize - Size())
+ m_offset = m_totalSize - Size();
+ if (m_offset < 0) m_offset = 0;
+}
+
+void CGUIControlGroupList::AddControl(CGUIControl *control, int position /*= -1*/)
+{
+ // NOTE: We override control navigation here, but we don't override the <onleft> etc. builtins
+ // if specified.
+ if (position < 0 || position > (int)m_children.size()) // add at the end
+ position = (int)m_children.size();
+
+ if (control)
+ { // set the navigation of items so that they form a list
+ int beforeID = (m_orientation == VERTICAL) ? GetControlIdUp() : GetControlIdLeft();
+ int afterID = (m_orientation == VERTICAL) ? GetControlIdDown() : GetControlIdRight();
+ if (m_children.size())
+ {
+ // we're inserting at the given position, so grab the items above and below and alter
+ // their navigation accordingly
+ CGUIControl *before = NULL;
+ CGUIControl *after = NULL;
+ if (position == 0)
+ { // inserting at the beginning
+ after = m_children[0];
+ if (afterID == GetID()) // we're wrapping around bottom->top, so we have to update the last item
+ before = m_children[m_children.size() - 1];
+ if (beforeID == GetID()) // we're wrapping around top->bottom
+ beforeID = m_children[m_children.size() - 1]->GetID();
+ afterID = after->GetID();
+ }
+ else if (position == (int)m_children.size())
+ { // inserting at the end
+ before = m_children[m_children.size() - 1];
+ if (beforeID == GetID()) // we're wrapping around top->bottom, so we have to update the first item
+ after = m_children[0];
+ if (afterID == GetID()) // we're wrapping around bottom->top
+ afterID = m_children[0]->GetID();
+ beforeID = before->GetID();
+ }
+ else
+ { // inserting somewhere in the middle
+ before = m_children[position - 1];
+ after = m_children[position];
+ beforeID = before->GetID();
+ afterID = after->GetID();
+ }
+ if (m_orientation == VERTICAL)
+ {
+ if (before) // update the DOWN action to point to us
+ before->SetNavigation(before->GetControlIdUp(), control->GetID(), GetControlIdLeft(), GetControlIdRight());
+ if (after) // update the UP action to point to us
+ after->SetNavigation(control->GetID(), after->GetControlIdDown(), GetControlIdLeft(), GetControlIdRight());
+ }
+ else
+ {
+ if (before) // update the RIGHT action to point to us
+ before->SetNavigation(GetControlIdUp(), GetControlIdDown(), before->GetControlIdLeft(), control->GetID());
+ if (after) // update the LEFT action to point to us
+ after->SetNavigation(GetControlIdUp(), GetControlIdDown(), control->GetID(), after->GetControlIdRight());
+ }
+ }
+ // now the control's nav
+ if (m_orientation == VERTICAL)
+ control->SetNavigation(beforeID, afterID, GetControlIdLeft(), GetControlIdRight());
+ else
+ control->SetNavigation(GetControlIdUp(), GetControlIdDown(), beforeID, afterID);
+
+ if (!m_useControlPositions)
+ control->SetPosition(0,0);
+ CGUIControlGroup::AddControl(control, position);
+ }
+}
+
+void CGUIControlGroupList::ClearAll()
+{
+ CGUIControlGroup::ClearAll();
+ m_offset = 0;
+}
+
+inline float CGUIControlGroupList::Size(const CGUIControl *control) const
+{
+ return (m_orientation == VERTICAL) ? control->GetYPosition() + control->GetHeight() : control->GetXPosition() + control->GetWidth();
+}
+
+inline float CGUIControlGroupList::Size() const
+{
+ return (m_orientation == VERTICAL) ? m_height : m_width;
+}
+
+void CGUIControlGroupList::ScrollTo(float offset)
+{
+ m_scrollOffset = offset;
+ m_scrollSpeed = (m_scrollOffset - m_offset) / TIME_TO_SCROLL;
+}
+
+bool CGUIControlGroupList::CanFocusFromPoint(const CPoint &point, CGUIControl **control, CPoint &controlPoint) const
+{
+ if (!CGUIControl::CanFocus()) return false;
+ float pos = 0;
+ CPoint controlCoords(point);
+ m_transform.InverseTransformPosition(controlCoords.x, controlCoords.y);
+ float alignOffset = GetAlignOffset();
+ for (ciControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ const CGUIControl *child = *it;
+ if (child->IsVisible())
+ {
+ if (pos + Size(child) > m_offset && pos < m_offset + Size())
+ { // we're on screen
+ float offsetX = m_orientation == VERTICAL ? m_posX : m_posX + alignOffset + pos - m_offset;
+ float offsetY = m_orientation == VERTICAL ? m_posY + alignOffset + pos - m_offset : m_posY;
+ if (child->CanFocusFromPoint(controlCoords - CPoint(offsetX, offsetY), control, controlPoint))
+ return true;
+ }
+ pos += Size(child) + m_itemGap;
+ }
+ }
+ *control = NULL;
+ return false;
+}
+
+void CGUIControlGroupList::UnfocusFromPoint(const CPoint &point)
+{
+ float pos = 0;
+ CPoint controlCoords(point);
+ m_transform.InverseTransformPosition(controlCoords.x, controlCoords.y);
+ float alignOffset = GetAlignOffset();
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *child = *it;
+ if (child->IsVisible())
+ {
+ if (pos + Size(child) > m_offset && pos < m_offset + Size())
+ { // we're on screen
+ CPoint offset = (m_orientation == VERTICAL) ? CPoint(m_posX, m_posY + alignOffset + pos - m_offset) : CPoint(m_posX + alignOffset + pos - m_offset, m_posY);
+ child->UnfocusFromPoint(controlCoords - offset);
+ }
+ pos += Size(child) + m_itemGap;
+ }
+ }
+ CGUIControl::UnfocusFromPoint(point);
+}
+
+bool CGUIControlGroupList::GetCondition(int condition, int data) const
+{
+ switch (condition)
+ {
+ case CONTAINER_HAS_NEXT:
+ return (m_totalSize >= Size() && m_offset < m_totalSize - Size());
+ case CONTAINER_HAS_PREVIOUS:
+ return (m_offset > 0);
+ default:
+ return false;
+ }
+}
+
+bool CGUIControlGroupList::IsFirstFocusableControl(const CGUIControl *control) const
+{
+ for (ciControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *child = *it;
+ if (child->IsVisible() && child->CanFocus())
+ { // found first focusable
+ return child == control;
+ }
+ }
+ return false;
+}
+
+bool CGUIControlGroupList::IsLastFocusableControl(const CGUIControl *control) const
+{
+ for (crControls it = m_children.rbegin(); it != m_children.rend(); ++it)
+ {
+ CGUIControl *child = *it;
+ if (child->IsVisible() && child->CanFocus())
+ { // found first focusable
+ return child == control;
+ }
+ }
+ return false;
+}
+
+float CGUIControlGroupList::GetAlignOffset() const
+{
+ if (m_totalSize < Size())
+ {
+ if (m_alignment & XBFONT_RIGHT)
+ return Size() - m_totalSize;
+ if (m_alignment & XBFONT_CENTER_X)
+ return (Size() - m_totalSize)*0.5f;
+ }
+ return 0.0f;
+}
diff --git a/guilib/GUIControlGroupList.h b/guilib/GUIControlGroupList.h
new file mode 100644
index 0000000000..e378a3adc0
--- /dev/null
+++ b/guilib/GUIControlGroupList.h
@@ -0,0 +1,74 @@
+/*!
+\file GUIControlGroupList.h
+\brief
+*/
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControlGroup.h"
+
+/*!
+ \ingroup controls
+ \brief list of controls that is scrollable
+ */
+class CGUIControlGroupList : public CGUIControlGroup
+{
+public:
+ CGUIControlGroupList(int parentID, int controlID, float posX, float posY, float width, float height, float itemGap, int pageControl, ORIENTATION orientation, bool useControlPositions, uint32_t alignment);
+ virtual ~CGUIControlGroupList(void);
+ virtual CGUIControlGroupList *Clone() const { return new CGUIControlGroupList(*this); };
+
+ virtual void Render();
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual bool CanFocusFromPoint(const CPoint &point, CGUIControl **control, CPoint &controlPoint) const;
+ virtual void UnfocusFromPoint(const CPoint &point);
+
+ virtual void AddControl(CGUIControl *control, int position = -1);
+ virtual void ClearAll();
+
+ virtual bool GetCondition(int condition, int data) const;
+protected:
+ bool IsFirstFocusableControl(const CGUIControl *control) const;
+ bool IsLastFocusableControl(const CGUIControl *control) const;
+ void ValidateOffset();
+ inline float Size(const CGUIControl *control) const;
+ inline float Size() const;
+ void ScrollTo(float offset);
+ float GetAlignOffset() const;
+
+ float m_itemGap;
+ int m_pageControl;
+
+ float m_offset; // measurement in pixels of our origin
+ float m_totalSize;
+
+ float m_scrollSpeed;
+ float m_scrollOffset;
+ DWORD m_scrollTime;
+
+ bool m_useControlPositions;
+ ORIENTATION m_orientation;
+ uint32_t m_alignment;
+};
+
diff --git a/guilib/GUIControlProfiler.cpp b/guilib/GUIControlProfiler.cpp
new file mode 100644
index 0000000000..f7071b088f
--- /dev/null
+++ b/guilib/GUIControlProfiler.cpp
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2005-2009 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControlProfiler.h"
+#include "tinyXML/tinyxml.h"
+
+bool CGUIControlProfiler::m_bIsRunning = false;
+
+CGUIControlProfilerItem::CGUIControlProfilerItem(CGUIControlProfiler *pProfiler, CGUIControlProfilerItem *pParent, CGUIControl *pControl)
+: m_pProfiler(pProfiler), m_pParent(pParent), m_pControl(pControl), m_dwVisTime(0), m_dwRenderTime(0)
+{
+ if (m_pControl)
+ {
+ m_controlID = m_pControl->GetID();
+ m_ControlType = m_pControl->GetControlType();
+ m_strDescription = m_pControl->GetDescription();
+ }
+ else
+ {
+ m_controlID = 0;
+ m_ControlType = CGUIControl::GUICONTROL_UNKNOWN;
+ }
+}
+
+CGUIControlProfilerItem::~CGUIControlProfilerItem(void)
+{
+ Reset(NULL);
+}
+
+void CGUIControlProfilerItem::Reset(CGUIControlProfiler *pProfiler)
+{
+ m_controlID = 0;
+ m_ControlType = CGUIControl::GUICONTROL_UNKNOWN;
+ m_pControl = NULL;
+
+ m_dwVisTime = 0;
+ m_dwRenderTime = 0;
+ const unsigned int dwSize = m_vecChildren.size();
+ for (unsigned int i=0; i<dwSize; ++i)
+ delete m_vecChildren[i];
+ m_vecChildren.clear();
+
+ m_pProfiler = pProfiler;
+}
+
+void CGUIControlProfilerItem::BeginVisibility(void)
+{
+ QueryPerformanceCounter(&m_i64VisStart);
+}
+
+void CGUIControlProfilerItem::EndVisibility(void)
+{
+ LARGE_INTEGER t2;
+ QueryPerformanceCounter(&t2);
+ m_dwVisTime += (DWORD)(m_pProfiler->m_fPerfScale * (t2.QuadPart - m_i64VisStart.QuadPart));
+}
+
+void CGUIControlProfilerItem::BeginRender(void)
+{
+ QueryPerformanceCounter(&m_i64RenderStart);
+}
+
+void CGUIControlProfilerItem::EndRender(void)
+{
+ LARGE_INTEGER t2;
+ QueryPerformanceCounter(&t2);
+ m_dwRenderTime += (DWORD)(m_pProfiler->m_fPerfScale * (t2.QuadPart - m_i64RenderStart.QuadPart));
+}
+
+void CGUIControlProfilerItem::SaveToXML(TiXmlElement *parent)
+{
+ TiXmlElement *xmlControl = new TiXmlElement("control");
+ parent->LinkEndChild(xmlControl);
+
+ const char *lpszType = NULL;
+ switch (m_ControlType)
+ {
+ case CGUIControl::GUICONTROL_BUTTON:
+ lpszType = "button"; break;
+ case CGUIControl::GUICONTROL_CHECKMARK:
+ lpszType = "checkmark"; break;
+ case CGUIControl::GUICONTROL_FADELABEL:
+ lpszType = "fadelabel"; break;
+ case CGUIControl::GUICONTROL_IMAGE:
+ case CGUIControl::GUICONTROL_BORDEREDIMAGE:
+ lpszType = "image"; break;
+ case CGUIControl::GUICONTROL_LARGE_IMAGE:
+ lpszType = "largeimage"; break;
+ case CGUIControl::GUICONTROL_LABEL:
+ lpszType = "label"; break;
+ case CGUIControl::GUICONTROL_LISTGROUP:
+ lpszType = "group"; break;
+ case CGUIControl::GUICONTROL_PROGRESS:
+ lpszType = "progress"; break;
+ case CGUIControl::GUICONTROL_RADIO:
+ lpszType = "radiobutton"; break;
+ case CGUIControl::GUICONTROL_RSS:
+ lpszType = "rss"; break;
+ case CGUIControl::GUICONTROL_SELECTBUTTON:
+ lpszType = "selectbutton"; break;
+ case CGUIControl::GUICONTROL_SLIDER:
+ lpszType = "slider"; break;
+ case CGUIControl::GUICONTROL_SETTINGS_SLIDER:
+ lpszType = "sliderex"; break;
+ case CGUIControl::GUICONTROL_SPIN:
+ lpszType = "spincontrol"; break;
+ case CGUIControl::GUICONTROL_SPINEX:
+ lpszType = "spincontrolex"; break;
+ case CGUIControl::GUICONTROL_TEXTBOX:
+ lpszType = "textbox"; break;
+ case CGUIControl::GUICONTROL_TOGGLEBUTTON:
+ lpszType = "togglebutton"; break;
+ case CGUIControl::GUICONTROL_VIDEO:
+ lpszType = "videowindow"; break;
+ case CGUIControl::GUICONTROL_MOVER:
+ lpszType = "mover"; break;
+ case CGUIControl::GUICONTROL_RESIZE:
+ lpszType = "resize"; break;
+ case CGUIControl::GUICONTROL_BUTTONBAR:
+ lpszType = "buttonscroller"; break;
+ case CGUIControl::GUICONTROL_EDIT:
+ lpszType = "edit"; break;
+ case CGUIControl::GUICONTROL_VISUALISATION:
+ lpszType = "visualisation"; break;
+ case CGUIControl::GUICONTROL_MULTI_IMAGE:
+ lpszType = "multiimage"; break;
+ case CGUIControl::GUICONTROL_GROUP:
+ lpszType = "group"; break;
+ case CGUIControl::GUICONTROL_GROUPLIST:
+ lpszType = "grouplist"; break;
+ case CGUIControl::GUICONTROL_SCROLLBAR:
+ lpszType = "scrollbar"; break;
+ case CGUIControl::GUICONTROL_LISTLABEL:
+ lpszType = "label"; break;
+ case CGUIControl::GUICONTROL_MULTISELECT:
+ lpszType = "multiselect"; break;
+ case CGUIControl::GUICONTAINER_LIST:
+ lpszType = "list"; break;
+ case CGUIControl::GUICONTAINER_WRAPLIST:
+ lpszType = "wraplist"; break;
+ case CGUIControl::GUICONTAINER_FIXEDLIST:
+ lpszType = "fixedlist"; break;
+ case CGUIControl::GUICONTAINER_PANEL:
+ lpszType = "panel"; break;
+ //case CGUIControl::GUICONTROL_LIST:
+ //case CGUIControl::GUICONTROL_UNKNOWN:
+ //case CGUIControl::GUICONTROL_LISTEX:
+ //case CGUIControl::GUICONTROL_SPINBUTTON:
+ //case CGUIControl::GUICONTROL_THUMBNAIL:
+ //case CGUIControl::GUICONTROL_CONSOLE:
+ default:
+ break;
+ }
+
+ if (lpszType)
+ xmlControl->SetAttribute("type", lpszType);
+ if (m_controlID != 0)
+ {
+ CStdString str;
+ str.Format("%u", m_controlID);
+ xmlControl->SetAttribute("id", str.c_str());
+ }
+
+ float pct = (float)GetTotalTime() / (float)m_pProfiler->GetTotalTime();
+ if (pct > 0.01f)
+ {
+ CStdString str;
+ str.Format("%.0f", pct * 100.0f);
+ xmlControl->SetAttribute("percent", str.c_str());
+ }
+
+ if (!m_strDescription.IsEmpty())
+ {
+ TiXmlElement *elem = new TiXmlElement("description");
+ xmlControl->LinkEndChild(elem);
+ TiXmlText *text = new TiXmlText(m_strDescription.c_str());
+ elem->LinkEndChild(text);
+ }
+
+ // Note time is stored in 1/100 milliseconds but reported in ms
+ DWORD dwVis = m_dwVisTime / 100;
+ DWORD dwRend = m_dwRenderTime / 100;
+ if (dwVis || dwRend)
+ {
+ CStdString val;
+ TiXmlElement *elem = new TiXmlElement("rendertime");
+ xmlControl->LinkEndChild(elem);
+ val.Format("%u", dwRend);
+ TiXmlText *text = new TiXmlText(val.c_str());
+ elem->LinkEndChild(text);
+
+ elem = new TiXmlElement("visibletime");
+ xmlControl->LinkEndChild(elem);
+ val.Format("%u", dwVis);
+ text = new TiXmlText(val.c_str());
+ elem->LinkEndChild(text);
+ }
+
+ if (m_vecChildren.size())
+ {
+ TiXmlElement *xmlChilds = new TiXmlElement("children");
+ xmlControl->LinkEndChild(xmlChilds);
+ const unsigned int dwSize = m_vecChildren.size();
+ for (unsigned int i=0; i<dwSize; ++i)
+ m_vecChildren[i]->SaveToXML(xmlChilds);
+ }
+}
+
+CGUIControlProfilerItem *CGUIControlProfilerItem::AddControl(CGUIControl *pControl)
+{
+ m_vecChildren.push_back(new CGUIControlProfilerItem(m_pProfiler, this, pControl));
+ return m_vecChildren.back();
+}
+
+CGUIControlProfilerItem *CGUIControlProfilerItem::FindOrAddControl(CGUIControl *pControl, bool recurse)
+{
+ const unsigned int dwSize = m_vecChildren.size();
+ for (unsigned int i=0; i<dwSize; ++i)
+ {
+ CGUIControlProfilerItem *p = m_vecChildren[i];
+ if (p->m_pControl == pControl)
+ return p;
+ if (recurse && (p = p->FindOrAddControl(pControl, true)))
+ return p;
+ }
+
+ if (pControl->GetParentControl() == m_pControl)
+ return AddControl(pControl);
+
+ return NULL;
+}
+
+CGUIControlProfiler::CGUIControlProfiler(void)
+: m_ItemHead(NULL, NULL, NULL), m_pLastItem(NULL), m_iMaxFrameCount(200)
+// m_bIsRunning(false), no isRunning because it is static
+{
+ LARGE_INTEGER i64PerfFreq;
+ QueryPerformanceFrequency(&i64PerfFreq);
+ m_fPerfScale = 100000.0f / i64PerfFreq.QuadPart;
+}
+
+CGUIControlProfiler &CGUIControlProfiler::Instance(void)
+{
+ static CGUIControlProfiler _instance;
+ return _instance;
+}
+
+bool CGUIControlProfiler::IsRunning(void)
+{
+ return m_bIsRunning;
+}
+
+void CGUIControlProfiler::Start(void)
+{
+ m_iFrameCount = 0;
+ m_bIsRunning = true;
+ m_pLastItem = NULL;
+ m_ItemHead.Reset(this);
+}
+
+void CGUIControlProfiler::BeginVisibility(CGUIControl *pControl)
+{
+ CGUIControlProfilerItem *item = FindOrAddControl(pControl);
+ item->BeginVisibility();
+}
+
+void CGUIControlProfiler::EndVisibility(CGUIControl *pControl)
+{
+ CGUIControlProfilerItem *item = FindOrAddControl(pControl);
+ item->EndVisibility();
+}
+
+void CGUIControlProfiler::BeginRender(CGUIControl *pControl)
+{
+ CGUIControlProfilerItem *item = FindOrAddControl(pControl);
+ item->BeginRender();
+}
+
+void CGUIControlProfiler::EndRender(CGUIControl *pControl)
+{
+ CGUIControlProfilerItem *item = FindOrAddControl(pControl);
+ item->EndRender();
+}
+
+CGUIControlProfilerItem *CGUIControlProfiler::FindOrAddControl(CGUIControl *pControl)
+{
+ if (m_pLastItem)
+ {
+ // Typically calls come in pairs so the last control we found is probably
+ // the one we want again next time
+ if (m_pLastItem->m_pControl == pControl)
+ return m_pLastItem;
+ // If that control is not a match, usually the one we want is the next
+ // sibling of that control, or the parent of that control so check
+ // the parent first as it is more convenient
+ m_pLastItem = m_pLastItem->m_pParent;
+ if (m_pLastItem && m_pLastItem->m_pControl == pControl)
+ return m_pLastItem;
+ // continued from above, this searches the original control's siblings
+ if (m_pLastItem)
+ m_pLastItem = m_pLastItem->FindOrAddControl(pControl, false);
+ if (m_pLastItem)
+ return m_pLastItem;
+ }
+
+ m_pLastItem = m_ItemHead.FindOrAddControl(pControl, true);
+ if (!m_pLastItem)
+ m_pLastItem = m_ItemHead.AddControl(pControl);
+
+ return m_pLastItem;
+}
+
+void CGUIControlProfiler::EndFrame(void)
+{
+ m_iFrameCount++;
+ if (m_iFrameCount >= m_iMaxFrameCount)
+ {
+ const unsigned int dwSize = m_ItemHead.m_vecChildren.size();
+ for (unsigned int i=0; i<dwSize; ++i)
+ {
+ CGUIControlProfilerItem *p = m_ItemHead.m_vecChildren[i];
+ m_ItemHead.m_dwVisTime += p->m_dwVisTime;
+ m_ItemHead.m_dwRenderTime += p->m_dwRenderTime;
+ }
+
+ m_bIsRunning = false;
+ if (SaveResults())
+ m_ItemHead.Reset(this);
+ }
+}
+
+bool CGUIControlProfiler::SaveResults(void)
+{
+ if (m_strOutputFile.IsEmpty())
+ return false;
+
+ TiXmlDocument doc;
+ TiXmlDeclaration decl("1.0", "", "yes");
+ doc.InsertEndChild(decl);
+
+ TiXmlElement *root = new TiXmlElement("guicontrolprofiler");
+ CStdString str;
+ str.Format("%d", m_iFrameCount);
+ root->SetAttribute("framecount", str.c_str());
+ root->SetAttribute("timeunit", "ms");
+ doc.LinkEndChild(root);
+
+ m_ItemHead.SaveToXML(root);
+ return doc.SaveFile(m_strOutputFile);
+}
diff --git a/guilib/GUIControlProfiler.h b/guilib/GUIControlProfiler.h
new file mode 100644
index 0000000000..48675e0179
--- /dev/null
+++ b/guilib/GUIControlProfiler.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2005-2009 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#ifndef GUILIB_GUICONTROLPROFILER_H__
+#define GUILIB_GUICONTROLPROFILER_H__
+#pragma once
+
+#include "GUIControl.h"
+
+class CGUIControlProfiler;
+class TiXmlElement;
+
+class CGUIControlProfilerItem
+{
+public:
+ CGUIControlProfiler *m_pProfiler;
+ CGUIControlProfilerItem * m_pParent;
+ CGUIControl *m_pControl;
+ std::vector<CGUIControlProfilerItem *> m_vecChildren;
+ CStdString m_strDescription;
+ int m_controlID;
+ CGUIControl::GUICONTROLTYPES m_ControlType;
+ DWORD m_dwVisTime;
+ DWORD m_dwRenderTime;
+ LARGE_INTEGER m_i64VisStart;
+ LARGE_INTEGER m_i64RenderStart;
+
+ CGUIControlProfilerItem(CGUIControlProfiler *pProfiler, CGUIControlProfilerItem *pParent, CGUIControl *pControl);
+ ~CGUIControlProfilerItem(void);
+
+ void Reset(CGUIControlProfiler *pProfiler);
+ void BeginVisibility(void);
+ void EndVisibility(void);
+ void BeginRender(void);
+ void EndRender(void);
+ void SaveToXML(TiXmlElement *parent);
+ DWORD GetTotalTime(void) const { return m_dwVisTime + m_dwRenderTime; };
+
+ CGUIControlProfilerItem *AddControl(CGUIControl *pControl);
+ CGUIControlProfilerItem *FindOrAddControl(CGUIControl *pControl, bool recurse);
+};
+
+class CGUIControlProfiler
+{
+public:
+ static CGUIControlProfiler &Instance(void);
+ static bool IsRunning(void);
+
+ void Start(void);
+ void EndFrame(void);
+ void BeginVisibility(CGUIControl *pControl);
+ void EndVisibility(CGUIControl *pControl);
+ void BeginRender(CGUIControl *pControl);
+ void EndRender(CGUIControl *pControl);
+ int GetMaxFrameCount(void) const { return m_iMaxFrameCount; };
+ void SetMaxFrameCount(int iMaxFrameCount) { m_iMaxFrameCount = iMaxFrameCount; };
+ void SetOutputFile(const CStdString &strOutputFile) { m_strOutputFile = strOutputFile; };
+ const CStdString &GetOutputFile(void) const { return m_strOutputFile; };
+ bool SaveResults(void);
+ DWORD GetTotalTime(void) const { return m_ItemHead.GetTotalTime(); };
+
+ float m_fPerfScale;
+private:
+ CGUIControlProfiler(void);
+ ~CGUIControlProfiler(void) {};
+ CGUIControlProfiler(const CGUIControlProfiler &that);
+ CGUIControlProfiler &operator=(const CGUIControlProfiler &that);
+
+ CGUIControlProfilerItem m_ItemHead;
+ CGUIControlProfilerItem *m_pLastItem;
+ CGUIControlProfilerItem *FindOrAddControl(CGUIControl *pControl);
+
+ static bool m_bIsRunning;
+ CStdString m_strOutputFile;
+ int m_iMaxFrameCount;
+ int m_iFrameCount;
+};
+
+#define GUIPROFILER_VISIBILITY_BEGIN(x) { if (CGUIControlProfiler::IsRunning()) CGUIControlProfiler::Instance().BeginVisibility(x); }
+#define GUIPROFILER_VISIBILITY_END(x) { if (CGUIControlProfiler::IsRunning()) CGUIControlProfiler::Instance().EndVisibility(x); }
+#define GUIPROFILER_RENDER_BEGIN(x) { if (CGUIControlProfiler::IsRunning()) CGUIControlProfiler::Instance().BeginRender(x); }
+#define GUIPROFILER_RENDER_END(x) { if (CGUIControlProfiler::IsRunning()) CGUIControlProfiler::Instance().EndRender(x); }
+
+#endif
diff --git a/guilib/GUIDialog.cpp b/guilib/GUIDialog.cpp
new file mode 100644
index 0000000000..1dd30a7129
--- /dev/null
+++ b/guilib/GUIDialog.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIDialog.h"
+#include "GUIWindowManager.h"
+#include "GUILabelControl.h"
+#include "GUIAudioManager.h"
+#include "utils/SingleLock.h"
+#include "Application.h"
+
+CGUIDialog::CGUIDialog(int id, const CStdString &xmlFile)
+ : CGUIWindow(id, xmlFile)
+{
+ m_bModal = true;
+ m_bRunning = false;
+ m_dialogClosing = false;
+ m_renderOrder = 1;
+ m_autoClosing = false;
+}
+
+CGUIDialog::~CGUIDialog(void)
+{}
+
+void CGUIDialog::OnWindowLoaded()
+{
+ CGUIWindow::OnWindowLoaded();
+
+ // Clip labels to extents
+ if (m_children.size())
+ {
+ CGUIControl* pBase = m_children[0];
+
+ for (iControls p = m_children.begin() + 1; p != m_children.end(); ++p)
+ {
+ if ((*p)->GetControlType() == CGUIControl::GUICONTROL_LABEL)
+ {
+ CGUILabelControl* pLabel = (CGUILabelControl*)(*p);
+
+ if (!pLabel->GetWidth())
+ {
+ float spacing = (pLabel->GetXPosition() - pBase->GetXPosition()) * 2;
+ pLabel->SetWidth(pBase->GetWidth() - spacing);
+ pLabel->SetTruncate(true);
+ }
+ }
+ }
+ }
+}
+
+bool CGUIDialog::OnAction(const CAction &action)
+{
+ if (action.id == ACTION_CLOSE_DIALOG || action.id == ACTION_PREVIOUS_MENU)
+ {
+ Close();
+ return true;
+ }
+ return CGUIWindow::OnAction(action);
+}
+
+bool CGUIDialog::OnMessage(CGUIMessage& message)
+{
+ switch ( message.GetMessage() )
+ {
+ case GUI_MSG_WINDOW_DEINIT:
+ {
+ CGUIWindow *pWindow = m_gWindowManager.GetWindow(m_gWindowManager.GetActiveWindow());
+ if (pWindow)
+ m_gWindowManager.ShowOverlay(pWindow->GetOverlayState());
+
+ CGUIWindow::OnMessage(message);
+ // if we were running, make sure we remove ourselves from the window manager
+ if (m_bRunning)
+ {
+ m_gWindowManager.RemoveDialog(GetID());
+ m_bRunning = false;
+ m_dialogClosing = false;
+ m_autoClosing = false;
+ }
+ return true;
+ }
+ case GUI_MSG_WINDOW_INIT:
+ {
+ CGUIWindow::OnMessage(message);
+ m_showStartTime = timeGetTime();
+ return true;
+ }
+ }
+
+ return CGUIWindow::OnMessage(message);
+}
+
+void CGUIDialog::Close(bool forceClose /*= false*/)
+{
+ //Lock graphic context here as it is sometimes called from non rendering threads
+ //maybe we should have a critical section per window instead??
+ CSingleLock lock(g_graphicsContext);
+
+ if (!m_bRunning) return;
+
+ // Play the window specific deinit sound
+ if(!m_dialogClosing)
+ g_audioManager.PlayWindowSound(GetID(), SOUND_DEINIT);
+
+ // don't close if we should be animating
+ if (!forceClose && HasAnimation(ANIM_TYPE_WINDOW_CLOSE))
+ {
+ if (!m_dialogClosing && !IsAnimating(ANIM_TYPE_WINDOW_CLOSE))
+ {
+ QueueAnimation(ANIM_TYPE_WINDOW_CLOSE);
+ m_dialogClosing = true;
+ }
+ return;
+ }
+
+ CGUIMessage msg(GUI_MSG_WINDOW_DEINIT, 0, 0);
+ OnMessage(msg);
+}
+
+void CGUIDialog::DoModal_Internal(int iWindowID /*= WINDOW_INVALID */, const CStdString &param /* = "" */)
+{
+ //Lock graphic context here as it is sometimes called from non rendering threads
+ //maybe we should have a critical section per window instead??
+ CSingleLock lock(g_graphicsContext);
+
+ m_dialogClosing = false;
+ m_bModal = true;
+ // set running before it's added to the window manager, else the auto-show code
+ // could show it as well if we are in a different thread from
+ // the main rendering thread (this should really be handled via
+ // a thread message though IMO)
+ m_bRunning = true;
+ m_gWindowManager.RouteToWindow(this);
+
+ // Play the window specific init sound
+ g_audioManager.PlayWindowSound(GetID(), SOUND_INIT);
+
+ // active this window...
+ CGUIMessage msg(GUI_MSG_WINDOW_INIT, 0, 0, WINDOW_INVALID, iWindowID);
+ msg.SetStringParam(param);
+ OnMessage(msg);
+
+// m_bRunning = true;
+
+ if (!m_windowLoaded)
+ Close(true);
+
+ lock.Leave();
+
+ while (m_bRunning && !g_application.m_bStop)
+ {
+ m_gWindowManager.Process();
+ }
+}
+
+void CGUIDialog::Show_Internal()
+{
+ //Lock graphic context here as it is sometimes called from non rendering threads
+ //maybe we should have a critical section per window instead??
+ CSingleLock lock(g_graphicsContext);
+
+ if (m_bRunning && !m_dialogClosing && !IsAnimating(ANIM_TYPE_WINDOW_CLOSE)) return;
+
+ m_bModal = false;
+
+ // set running before it's added to the window manager, else the auto-show code
+ // could show it as well if we are in a different thread from
+ // the main rendering thread (this should really be handled via
+ // a thread message though IMO)
+ m_bRunning = true;
+ m_dialogClosing = false;
+ m_gWindowManager.AddModeless(this);
+
+ // Play the window specific init sound
+ g_audioManager.PlayWindowSound(GetID(), SOUND_INIT);
+
+ // active this window...
+ CGUIMessage msg(GUI_MSG_WINDOW_INIT, 0, 0);
+ OnMessage(msg);
+
+// m_bRunning = true;
+}
+
+void CGUIDialog::DoModal(int iWindowID /*= WINDOW_INVALID */, const CStdString &param)
+{
+ g_application.getApplicationMessenger().DoModal(this, iWindowID, param);
+}
+
+void CGUIDialog::Show()
+{
+ g_application.getApplicationMessenger().Show(this);
+}
+
+bool CGUIDialog::RenderAnimation(DWORD time)
+{
+ CGUIWindow::RenderAnimation(time);
+ return m_bRunning;
+}
+
+void CGUIDialog::Render()
+{
+ CGUIWindow::Render();
+ // Check to see if we should close at this point
+ // We check after the controls have finished rendering, as we may have to close due to
+ // the controls rendering after the window has finished it's animation
+ // we call the base class instead of this class so that we can find the change
+ if (m_dialogClosing && !CGUIWindow::IsAnimating(ANIM_TYPE_WINDOW_CLOSE))
+ {
+ Close(true);
+ }
+
+ if (m_autoClosing && m_showStartTime + m_showDuration < timeGetTime() && !m_dialogClosing)
+ {
+ Close();
+ }
+}
+
+bool CGUIDialog::IsAnimating(ANIMATION_TYPE animType)
+{
+ if (animType == ANIM_TYPE_WINDOW_CLOSE)
+ return m_dialogClosing;
+ return CGUIWindow::IsAnimating(animType);
+}
+
+void CGUIDialog::SetDefaults()
+{
+ CGUIWindow::SetDefaults();
+ m_renderOrder = 1;
+}
+
+void CGUIDialog::SetAutoClose(unsigned int timeoutMs)
+{
+ m_autoClosing = true;
+ m_showDuration = timeoutMs;
+ if (m_bRunning)
+ m_showStartTime = timeGetTime();
+}
+
+
diff --git a/guilib/GUIDialog.h b/guilib/GUIDialog.h
new file mode 100644
index 0000000000..e80ace3b6e
--- /dev/null
+++ b/guilib/GUIDialog.h
@@ -0,0 +1,73 @@
+/*!
+\file GUIDialog.h
+\brief
+*/
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIWindow.h"
+#include "Key.h"
+
+/*!
+ \ingroup winmsg
+ \brief
+ */
+class CGUIDialog :
+ public CGUIWindow
+{
+public:
+ CGUIDialog(int id, const CStdString &xmlFile);
+ virtual ~CGUIDialog(void);
+
+ virtual bool OnAction(const CAction &action);
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual void Render();
+
+ void DoModal(int iWindowID = WINDOW_INVALID, const CStdString &param = ""); // modal
+ void Show(); // modeless
+
+ virtual void Close(bool forceClose = false);
+ virtual bool IsDialogRunning() const { return m_bRunning; };
+ virtual bool IsDialog() const { return true;};
+ virtual bool IsModalDialog() const { return m_bModal; };
+
+ virtual bool IsAnimating(ANIMATION_TYPE animType);
+
+ void SetAutoClose(unsigned int timeoutMs);
+protected:
+ virtual bool RenderAnimation(DWORD time);
+ virtual void SetDefaults();
+ virtual void OnWindowLoaded();
+
+ friend class CApplicationMessenger;
+ void DoModal_Internal(int iWindowID = WINDOW_INVALID, const CStdString &param = ""); // modal
+ void Show_Internal(); // modeless
+
+ bool m_bRunning;
+ bool m_bModal;
+ bool m_dialogClosing;
+ bool m_autoClosing;
+ DWORD m_showStartTime;
+ DWORD m_showDuration;
+};
diff --git a/guilib/GUIEditControl.cpp b/guilib/GUIEditControl.cpp
new file mode 100644
index 0000000000..604ca384a0
--- /dev/null
+++ b/guilib/GUIEditControl.cpp
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIEditControl.h"
+#include "utils/CharsetConverter.h"
+#include "GUIDialogKeyboard.h"
+#include "GUIDialogNumeric.h"
+#include "LocalizeStrings.h"
+#include "DateTime.h"
+
+#ifdef __APPLE__
+#include "CocoaInterface.h"
+#endif
+
+using namespace std;
+
+#ifdef WIN32
+extern HWND g_hWnd;
+#endif
+
+CGUIEditControl::CGUIEditControl(int parentID, int controlID, float posX, float posY,
+ float width, float height, const CTextureInfo &textureFocus, const CTextureInfo &textureNoFocus,
+ const CLabelInfo& labelInfo, const std::string &text)
+ : CGUIButtonControl(parentID, controlID, posX, posY, width, height, textureFocus, textureNoFocus, labelInfo)
+{
+ ControlType = GUICONTROL_EDIT;
+ m_textOffset = 0;
+ m_textWidth = width;
+ m_cursorPos = 0;
+ m_cursorBlink = 0;
+ m_inputHeading = 0;
+ m_inputType = INPUT_TYPE_TEXT;
+ SetLabel(text);
+}
+
+CGUIEditControl::CGUIEditControl(const CGUIButtonControl &button)
+ : CGUIButtonControl(button)
+{
+ ControlType = GUICONTROL_EDIT;
+ SetLabel(m_info.GetLabel(GetParentID()));
+ m_textOffset = 0;
+ m_textWidth = GetWidth();
+ m_cursorPos = 0;
+ m_cursorBlink = 0;
+}
+
+CGUIEditControl::~CGUIEditControl(void)
+{
+}
+
+bool CGUIEditControl::OnMessage(CGUIMessage &message)
+{
+ if (message.GetMessage() == GUI_MSG_SET_TYPE)
+ {
+ SetInputType((INPUT_TYPE)message.GetParam1(), (int)message.GetParam2());
+ return true;
+ }
+ else if (message.GetMessage() == GUI_MSG_ITEM_SELECTED)
+ {
+ message.SetLabel(GetLabel2());
+ return true;
+ }
+ return CGUIButtonControl::OnMessage(message);
+}
+
+bool CGUIEditControl::OnAction(const CAction &action)
+{
+ ValidateCursor();
+
+ // TODO: We shouldn't really need to test for ACTION_PARENT_DIR here
+ // but it may currently be useful as we can't map specific to an
+ // edit control other than the keyboard (which doesn't use this block)
+ if (action.id == ACTION_BACKSPACE || action.id == ACTION_PARENT_DIR)
+ {
+ // backspace
+ if (m_cursorPos)
+ {
+ m_text2.erase(--m_cursorPos, 1);
+ OnTextChanged();
+ }
+ return true;
+ }
+ else if (action.id == ACTION_MOVE_LEFT)
+ {
+ if (m_cursorPos > 0)
+ {
+ m_cursorPos--;
+ OnTextChanged();
+ return true;
+ }
+ }
+ else if (action.id == ACTION_MOVE_RIGHT)
+ {
+ if ((unsigned int) m_cursorPos < m_text2.size())
+ {
+ m_cursorPos++;
+ OnTextChanged();
+ return true;
+ }
+ }
+ else if (action.id == ACTION_PASTE)
+ {
+#ifdef __APPLE__
+ const char *szStr = Cocoa_Paste();
+ if (szStr)
+ {
+ m_text2 += szStr;
+ m_cursorPos+=strlen(szStr);
+ OnTextChanged();
+ }
+#elif defined _WIN32
+ HGLOBAL hglb;
+ LPTSTR lptstr;
+ if (OpenClipboard(g_hWnd))
+ {
+ hglb = GetClipboardData(CF_TEXT);
+ if (hglb != NULL)
+ {
+ lptstr = (LPTSTR)GlobalLock(hglb);
+ if (lptstr != NULL)
+ {
+ m_text2 = (char*)lptstr;
+ GlobalUnlock(hglb);
+ }
+ }
+ CloseClipboard();
+ OnTextChanged();
+ }
+#endif
+ }
+ else if (action.id >= KEY_VKEY && action.id < KEY_ASCII)
+ {
+ // input from the keyboard (vkey, not ascii)
+ BYTE b = action.id & 0xFF;
+ if (b == 0x25 && m_cursorPos > 0)
+ { // left
+ m_cursorPos--;
+ OnTextChanged();
+ return true;
+ }
+ if (b == 0x27 && m_cursorPos < m_text2.length())
+ { // right
+ m_cursorPos++;
+ OnTextChanged();
+ return true;
+ }
+ if (b == 0x2e)
+ {
+ if (m_cursorPos < m_text2.length())
+ { // delete
+ m_text2.erase(m_cursorPos, 1);
+ OnTextChanged();
+ return true;
+ }
+ }
+ if (b == 0x8)
+ {
+ if (m_cursorPos > 0)
+ { // backspace
+ m_text2.erase(--m_cursorPos, 1);
+ OnTextChanged();
+ }
+ return true;
+ }
+ }
+ else if (action.id >= KEY_ASCII)
+ {
+ // input from the keyboard
+ switch (action.unicode)
+ {
+ case '\t':
+ break;
+ case 10:
+ case 13:
+ {
+ // enter - send click message, but otherwise ignore
+ SEND_CLICK_MESSAGE(GetID(), GetParentID(), 1);
+ return true;
+ }
+ case 27:
+ { // escape - fallthrough to default action
+ return CGUIButtonControl::OnAction(action);
+ }
+ case 8:
+ {
+ // backspace
+ if (m_cursorPos)
+ {
+ m_text2.erase(--m_cursorPos, 1);
+ OnTextChanged();
+ }
+ break;
+ }
+ default:
+ {
+ m_text2.insert(m_text2.begin() + m_cursorPos, (WCHAR)action.unicode);
+ m_cursorPos++;
+ OnTextChanged();
+ break;
+ }
+ }
+ OnTextChanged();
+ return true;
+ }
+ else if (action.id >= REMOTE_2 && action.id <= REMOTE_9)
+ { // input from the remote
+ if (m_inputType == INPUT_TYPE_FILTER)
+ { // filtering - use single number presses
+ m_text2.insert(m_text2.begin() + m_cursorPos, L'0' + (action.id - REMOTE_0));
+ m_cursorPos++;
+ OnTextChanged();
+ return true;
+ }
+ }
+ return CGUIButtonControl::OnAction(action);
+}
+
+void CGUIEditControl::OnClick()
+{
+ // we received a click - it's not from the keyboard, so pop up the virtual keyboard, unless
+ // that is where we reside!
+ if (GetParentID() == WINDOW_DIALOG_KEYBOARD)
+ return;
+
+ CStdString utf8;
+ g_charsetConverter.wToUTF8(m_text2, utf8);
+ bool textChanged = false;
+ CStdString heading = g_localizeStrings.Get(m_inputHeading ? m_inputHeading : 16028);
+ switch (m_inputType)
+ {
+ case INPUT_TYPE_NUMBER:
+ textChanged = CGUIDialogNumeric::ShowAndGetNumber(utf8, heading);
+ break;
+ case INPUT_TYPE_SECONDS:
+ textChanged = CGUIDialogNumeric::ShowAndGetSeconds(utf8, g_localizeStrings.Get(21420));
+ break;
+ case INPUT_TYPE_DATE:
+ {
+ CDateTime dateTime;
+ dateTime.SetFromDBDate(utf8);
+ if (dateTime < CDateTime(2000,1, 1, 0, 0, 0))
+ dateTime = CDateTime(2000, 1, 1, 0, 0, 0);
+ SYSTEMTIME date;
+ dateTime.GetAsSystemTime(date);
+ if (CGUIDialogNumeric::ShowAndGetDate(date, g_localizeStrings.Get(21420)))
+ {
+ dateTime = CDateTime(date);
+ utf8 = dateTime.GetAsDBDate();
+ textChanged = true;
+ }
+ break;
+ }
+ case INPUT_TYPE_IPADDRESS:
+ textChanged = CGUIDialogNumeric::ShowAndGetIPAddress(utf8, heading);
+ break;
+ case INPUT_TYPE_SEARCH:
+ CGUIDialogKeyboard::ShowAndGetFilter(utf8, true);
+ break;
+ case INPUT_TYPE_FILTER:
+ CGUIDialogKeyboard::ShowAndGetFilter(utf8, false);
+ break;
+ case INPUT_TYPE_TEXT:
+ default:
+ textChanged = CGUIDialogKeyboard::ShowAndGetInput(utf8, heading, true, m_inputType == INPUT_TYPE_PASSWORD);
+ break;
+ }
+ if (textChanged)
+ {
+ g_charsetConverter.utf8ToW(utf8, m_text2);
+ m_cursorPos = m_text2.size();
+ OnTextChanged();
+ m_cursorPos = m_text2.size();
+ }
+}
+
+void CGUIEditControl::SetInputType(CGUIEditControl::INPUT_TYPE type, int heading)
+{
+ m_inputType = type;
+ m_inputHeading = heading;
+ // TODO: Verify the current input string?
+}
+
+void CGUIEditControl::RecalcLabelPosition()
+{
+ if (!m_label.font) return;
+
+ // ensure that our cursor is within our width
+ ValidateCursor();
+
+ CStdStringW text = GetDisplayedText();
+ m_textWidth = m_textLayout2.GetTextWidth(text + L'|');
+ float beforeCursorWidth = m_textLayout2.GetTextWidth(text.Left(m_cursorPos));
+ float afterCursorWidth = m_textLayout2.GetTextWidth(text.Left(m_cursorPos) + L'|');
+ float leftTextWidth = m_textLayout.GetTextWidth();
+ float maxTextWidth = m_width - m_label.offsetX*2;
+ if (leftTextWidth > 0)
+ maxTextWidth -= leftTextWidth + spaceWidth;
+
+ // if skinner forgot to set height :p
+ if (m_height == 0)
+ m_height = 2*m_label.font->GetTextHeight(1);
+
+ if (m_textWidth > maxTextWidth)
+ { // we render taking up the full width, so make sure our cursor position is
+ // within the render window
+ if (m_textOffset + afterCursorWidth > maxTextWidth)
+ {
+ // move the position to the left (outside of the viewport)
+ m_textOffset = maxTextWidth - afterCursorWidth;
+ }
+ else if (m_textOffset + beforeCursorWidth < 0) // offscreen to the left
+ {
+ // otherwise use original position
+ m_textOffset = -beforeCursorWidth;
+ }
+ else if (m_textOffset + m_textWidth < maxTextWidth)
+ { // we have more text than we're allowed, but we aren't filling all the space
+ m_textOffset = maxTextWidth - m_textWidth;
+ }
+ }
+ else
+ m_textOffset = 0;
+}
+
+void CGUIEditControl::RenderText()
+{
+ if (m_bInvalidated)
+ RecalcLabelPosition();
+
+ float leftTextWidth = m_textLayout.GetTextWidth();
+ float maxTextWidth = m_width - m_label.offsetX * 2;
+
+ // start by rendering the normal text
+ float posX = m_posX + m_label.offsetX;
+ float posY = m_posY;
+ uint32_t align = m_label.align & XBFONT_CENTER_Y;
+
+ if (m_label.align & XBFONT_CENTER_Y)
+ posY += m_height*0.5f;
+
+ if (leftTextWidth > 0)
+ {
+ // render the text on the left
+ if (IsDisabled())
+ m_textLayout.Render(posX, posY, m_label.angle, m_label.disabledColor, m_label.shadowColor, align, leftTextWidth, true);
+ else if (HasFocus() && m_label.focusedColor)
+ m_textLayout.Render(posX, posY, m_label.angle, m_label.focusedColor, m_label.shadowColor, align, leftTextWidth);
+ else
+ m_textLayout.Render(posX, posY, m_label.angle, m_label.textColor, m_label.shadowColor, align, leftTextWidth);
+
+ posX += leftTextWidth + spaceWidth;
+ maxTextWidth -= leftTextWidth + spaceWidth;
+ }
+
+ if (g_graphicsContext.SetClipRegion(posX, m_posY, maxTextWidth, m_height))
+ {
+ if (m_textWidth < maxTextWidth)
+ { // align text as our text fits
+ if (leftTextWidth > 0)
+ { // right align as we have 2 labels
+ posX = m_posX + m_width - m_label.offsetX;
+ align |= XBFONT_RIGHT;
+ }
+ else
+ { // align by whatever the skinner requests
+ if (m_label.align & XBFONT_CENTER_X)
+ posX += 0.5f*maxTextWidth;
+ if (m_label.align & XBFONT_RIGHT)
+ posX += maxTextWidth;
+ align |= (m_label.align & 3);
+ }
+ }
+ CStdStringW text = GetDisplayedText();
+ // let's render it ourselves
+ if (HasFocus())
+ { // cursor location assumes utf16 text, so deal with that (inefficient, but it's not as if it's a high-use area
+ // virtual keyboard only)
+ CStdStringW col;
+ if ((m_dwFocusCounter % 64) > 32)
+ col.Format(L"|");
+ else
+ col.Format(L"[COLOR %x]|[/COLOR]", 0x1000000);
+ text.Insert(m_cursorPos, col);
+ }
+
+ m_textLayout2.SetText(text);
+
+ if (IsDisabled())
+ m_textLayout2.Render(posX + m_textOffset, posY, m_label.angle, m_label.disabledColor, m_label.shadowColor, align, m_textWidth, true);
+ else if (HasFocus() && m_label.focusedColor)
+ m_textLayout2.Render(posX + m_textOffset, posY, m_label.angle, m_label.focusedColor, m_label.shadowColor, align, m_textWidth);
+ else
+ m_textLayout2.Render(posX + m_textOffset, posY, m_label.angle, m_label.textColor, m_label.shadowColor, align, m_textWidth);
+
+ g_graphicsContext.RestoreClipRegion();
+ }
+}
+
+CStdStringW CGUIEditControl::GetDisplayedText() const
+{
+ if (m_inputType == INPUT_TYPE_PASSWORD)
+ {
+ CStdStringW text;
+ text.append(m_text2.size(), L'*');
+ return text;
+ }
+ return m_text2;
+}
+
+void CGUIEditControl::ValidateCursor()
+{
+ if (m_cursorPos > m_text2.size())
+ m_cursorPos = m_text2.size();
+}
+
+void CGUIEditControl::OnTextChanged()
+{
+ SEND_CLICK_MESSAGE(GetID(), GetParentID(), 0);
+
+ vector<CGUIActionDescriptor> textChangeActions = m_textChangeActions;
+ for (unsigned int i = 0; i < textChangeActions.size(); i++)
+ {
+ CGUIMessage message(GUI_MSG_EXECUTE, GetID(), GetParentID());
+ message.SetAction(textChangeActions[i]);
+ g_graphicsContext.SendMessage(message);
+ }
+
+ SetInvalid();
+}
+
+void CGUIEditControl::SetLabel(const std::string &text)
+{
+ m_textLayout.Update(text);
+ SetInvalid();
+}
+
+void CGUIEditControl::SetLabel2(const std::string &text)
+{
+ CStdStringW newText;
+ g_charsetConverter.utf8ToW(text, newText);
+ if (newText != m_text2)
+ {
+ m_text2 = newText;
+ m_cursorPos = m_text2.size();
+ SetInvalid();
+ }
+}
+
+CStdString CGUIEditControl::GetLabel2() const
+{
+ CStdString text;
+ g_charsetConverter.wToUTF8(m_text2, text);
+ return text;
+}
+
+unsigned int CGUIEditControl::GetCursorPosition() const
+{
+ return m_cursorPos;
+}
+
+void CGUIEditControl::SetCursorPosition(unsigned int iPosition)
+{
+ m_cursorPos = iPosition;
+}
diff --git a/guilib/GUIEditControl.h b/guilib/GUIEditControl.h
new file mode 100644
index 0000000000..8f8b75ad12
--- /dev/null
+++ b/guilib/GUIEditControl.h
@@ -0,0 +1,100 @@
+/*!
+\file GUIEditControl.h
+\brief
+*/
+
+#ifndef GUILIB_GUIEditControl_H
+#define GUILIB_GUIEditControl_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIButtonControl.h"
+
+/*!
+ \ingroup controls
+ \brief
+ */
+
+class CGUIEditControl : public CGUIButtonControl
+{
+public:
+ enum INPUT_TYPE {
+ INPUT_TYPE_TEXT = 0,
+ INPUT_TYPE_NUMBER,
+ INPUT_TYPE_SECONDS,
+ INPUT_TYPE_DATE,
+ INPUT_TYPE_IPADDRESS,
+ INPUT_TYPE_PASSWORD,
+ INPUT_TYPE_SEARCH,
+ INPUT_TYPE_FILTER
+ };
+
+ CGUIEditControl(int parentID, int controlID, float posX, float posY,
+ float width, float height, const CTextureInfo &textureFocus, const CTextureInfo &textureNoFocus,
+ const CLabelInfo& labelInfo, const std::string &text);
+ CGUIEditControl(const CGUIButtonControl &button);
+ virtual ~CGUIEditControl(void);
+ virtual CGUIEditControl *Clone() const { return new CGUIEditControl(*this); };
+
+ virtual bool OnMessage(CGUIMessage &message);
+ virtual bool OnAction(const CAction &action);
+ virtual void OnClick();
+
+ virtual void SetLabel(const std::string &text);
+ virtual void SetLabel2(const std::string &text);
+
+ virtual CStdString GetLabel2() const;
+
+ unsigned int GetCursorPosition() const;
+ void SetCursorPosition(unsigned int iPosition);
+
+ void SetInputType(INPUT_TYPE type, int heading);
+
+ void SetTextChangeActions(const std::vector<CGUIActionDescriptor>& textChangeActions) { m_textChangeActions = textChangeActions; };
+
+ bool HasTextChangeActions() { return m_textChangeActions.size() > 0; };
+
+protected:
+ virtual void RenderText();
+ CStdStringW GetDisplayedText() const;
+ void RecalcLabelPosition();
+ void ValidateCursor();
+ void OnTextChanged();
+
+ CStdStringW m_text2;
+ CStdString m_text;
+ float m_textOffset;
+ float m_textWidth;
+
+ static const int spaceWidth = 5;
+
+ unsigned int m_cursorPos;
+ unsigned int m_cursorBlink;
+
+ int m_inputHeading;
+ INPUT_TYPE m_inputType;
+
+ std::vector<CGUIActionDescriptor> m_textChangeActions;
+};
+#endif
diff --git a/guilib/GUIFadeLabelControl.cpp b/guilib/GUIFadeLabelControl.cpp
new file mode 100644
index 0000000000..195740434e
--- /dev/null
+++ b/guilib/GUIFadeLabelControl.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIFadeLabelControl.h"
+#include "utils/CharsetConverter.h"
+
+using namespace std;
+
+CGUIFadeLabelControl::CGUIFadeLabelControl(int parentID, int controlID, float posX, float posY, float width, float height, const CLabelInfo& labelInfo, bool scrollOut, int scrollSpeed, DWORD timeToDelayAtEnd, bool resetOnLabelChange)
+ : CGUIControl(parentID, controlID, posX, posY, width, height), m_scrollInfo(50, labelInfo.offsetX, scrollSpeed)
+ , m_textLayout(labelInfo.font, false)
+{
+ m_label = labelInfo;
+ m_currentLabel = 0;
+ ControlType = GUICONTROL_FADELABEL;
+ m_scrollOut = scrollOut;
+ m_fadeAnim = CAnimation::CreateFader(100, 0, timeToDelayAtEnd, 200);
+ if (m_fadeAnim)
+ m_fadeAnim->ApplyAnimation();
+ m_renderTime = 0;
+ m_lastLabel = -1;
+ m_scrollSpeed = scrollSpeed; // save it for later
+ m_resetOnLabelChange = resetOnLabelChange;
+ m_shortText = false;
+}
+
+CGUIFadeLabelControl::CGUIFadeLabelControl(const CGUIFadeLabelControl &from)
+: CGUIControl(from), m_infoLabels(from.m_infoLabels), m_scrollInfo(from.m_scrollInfo), m_textLayout(from.m_textLayout)
+{
+ m_label = from.m_label;
+ m_scrollOut = from.m_scrollOut;
+ m_scrollSpeed = from.m_scrollSpeed;
+ m_resetOnLabelChange = from.m_resetOnLabelChange;
+
+ if (from.m_fadeAnim)
+ m_fadeAnim = new CAnimation(*from.m_fadeAnim);
+ if (m_fadeAnim)
+ m_fadeAnim->ApplyAnimation();
+ m_currentLabel = 0;
+ m_renderTime = 0;
+ m_lastLabel = -1;
+ ControlType = GUICONTROL_FADELABEL;
+}
+
+CGUIFadeLabelControl::~CGUIFadeLabelControl(void)
+{
+ delete m_fadeAnim;
+}
+
+void CGUIFadeLabelControl::SetInfo(const vector<CGUIInfoLabel> &infoLabels)
+{
+ m_lastLabel = -1;
+ m_infoLabels = infoLabels;
+}
+
+void CGUIFadeLabelControl::AddLabel(const string &label)
+{
+ m_infoLabels.push_back(CGUIInfoLabel(label));
+}
+
+void CGUIFadeLabelControl::DoRender(DWORD currentTime)
+{
+ m_renderTime = currentTime;
+ CGUIControl::DoRender(currentTime);
+}
+
+void CGUIFadeLabelControl::UpdateColors()
+{
+ m_label.UpdateColors();
+ CGUIControl::UpdateColors();
+}
+
+void CGUIFadeLabelControl::Render()
+{
+ if (m_infoLabels.size() == 0)
+ { // nothing to render
+ CGUIControl::Render();
+ return ;
+ }
+
+ if (m_currentLabel >= m_infoLabels.size() )
+ m_currentLabel = 0;
+
+ if (m_textLayout.Update(m_infoLabels[m_currentLabel].GetLabel(m_parentID)))
+ { // changed label - update our suffix based on length of available text
+ float width, height;
+ m_textLayout.GetTextExtent(width, height);
+ float spaceWidth = m_label.font->GetCharWidth(L' ');
+ unsigned int numSpaces = (unsigned int)(m_width / spaceWidth) + 1;
+ if (width < m_width) // append spaces for scrolling
+ numSpaces += (unsigned int)((m_width - width) / spaceWidth) + 1;
+ m_shortText = (width + m_label.offsetX) < m_width;
+ m_scrollInfo.suffix.assign(numSpaces, L' ');
+ if (m_resetOnLabelChange)
+ {
+ m_scrollInfo.Reset();
+ m_fadeAnim->ResetAnimation();
+ }
+ }
+ if (m_currentLabel != m_lastLabel)
+ { // new label - reset scrolling
+ m_scrollInfo.Reset();
+ m_fadeAnim->QueueAnimation(ANIM_PROCESS_REVERSE);
+ m_lastLabel = m_currentLabel;
+ }
+
+ float posY = m_posY;
+ if (m_label.align & XBFONT_CENTER_Y)
+ posY += m_height * 0.5f;
+ if (m_infoLabels.size() == 1 && m_shortText)
+ { // single label set and no scrolling required - just display
+ m_textLayout.Render(m_posX + m_label.offsetX, posY, 0, m_label.textColor, m_label.shadowColor, (m_label.align & ~3), m_width - m_label.offsetX);
+ CGUIControl::Render();
+ return;
+ }
+
+ bool moveToNextLabel = false;
+ if (!m_scrollOut)
+ {
+ vecText text;
+ m_textLayout.GetFirstText(text);
+ if (m_scrollInfo.characterPos && m_scrollInfo.characterPos < text.size())
+ text.erase(text.begin(), text.begin() + min((int)m_scrollInfo.characterPos - 1, (int)text.size()));
+ if (m_label.font->GetTextWidth(text) < m_width)
+ {
+ if (m_fadeAnim->GetProcess() != ANIM_PROCESS_NORMAL)
+ m_fadeAnim->QueueAnimation(ANIM_PROCESS_NORMAL);
+ moveToNextLabel = true;
+ }
+ }
+ else if (m_scrollInfo.characterPos > m_textLayout.GetTextLength())
+ moveToNextLabel = true;
+
+ // apply the fading animation
+ TransformMatrix matrix;
+ m_fadeAnim->Animate(m_renderTime, true);
+ m_fadeAnim->RenderAnimation(matrix);
+ g_graphicsContext.AddTransform(matrix);
+
+ if (m_fadeAnim->GetState() == ANIM_STATE_APPLIED)
+ m_fadeAnim->ResetAnimation();
+
+ m_scrollInfo.SetSpeed((m_fadeAnim->GetProcess() == ANIM_PROCESS_NONE) ? m_scrollSpeed : 0);
+
+ if (!m_scrollOut && m_shortText)
+ {
+ float posX = m_posX + m_label.offsetX;
+ if (m_label.align & XBFONT_CENTER_X)
+ posX = m_posX + m_width * 0.5f;
+ else if (m_label.align & XBFONT_RIGHT)
+ posX = m_posX + m_width;
+ m_textLayout.Render(posX, posY, 0, m_label.textColor, m_label.shadowColor, m_label.align, m_width);
+ }
+ else
+ m_textLayout.RenderScrolling(m_posX, posY, 0, m_label.textColor, m_label.shadowColor, (m_label.align & ~3), m_width, m_scrollInfo);
+
+ if (moveToNextLabel)
+ { // increment the label and reset scrolling
+ if (m_fadeAnim->GetProcess() != ANIM_PROCESS_NORMAL)
+ {
+ unsigned int label = m_currentLabel;
+ do
+ { // cycle until we get a non-empty label, or stick with the one we have
+ label++;
+ if (label >= m_infoLabels.size())
+ label = 0;
+ }
+ while (label != m_currentLabel && m_infoLabels[label].GetLabel(m_parentID).IsEmpty());
+ m_currentLabel = label;
+ m_scrollInfo.Reset();
+ m_fadeAnim->QueueAnimation(ANIM_PROCESS_REVERSE);
+ }
+ }
+
+ g_graphicsContext.RemoveTransform();
+
+ CGUIControl::Render();
+}
+
+
+bool CGUIFadeLabelControl::CanFocus() const
+{
+ return false;
+}
+
+
+bool CGUIFadeLabelControl::OnMessage(CGUIMessage& message)
+{
+ if ( message.GetControlId() == GetID() )
+ {
+ if (message.GetMessage() == GUI_MSG_LABEL_ADD)
+ {
+ AddLabel(message.GetLabel());
+ }
+ if (message.GetMessage() == GUI_MSG_LABEL_RESET)
+ {
+ m_lastLabel = -1;
+ m_infoLabels.clear();
+ m_scrollInfo.Reset();
+ }
+ if (message.GetMessage() == GUI_MSG_LABEL_SET)
+ {
+ m_lastLabel = -1;
+ m_infoLabels.clear();
+ m_scrollInfo.Reset();
+ AddLabel(message.GetLabel());
+ }
+ }
+ return CGUIControl::OnMessage(message);
+}
+
diff --git a/guilib/GUIFadeLabelControl.h b/guilib/GUIFadeLabelControl.h
new file mode 100644
index 0000000000..bfa73d9557
--- /dev/null
+++ b/guilib/GUIFadeLabelControl.h
@@ -0,0 +1,75 @@
+/*!
+\file GUIFadeLabelControl.h
+\brief
+*/
+
+#ifndef GUILIB_GUIFADELABELCONTROL_H
+#define GUILIB_GUIFADELABELCONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+
+#include "GUILabelControl.h" // for CInfoPortion
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIFadeLabelControl : public CGUIControl
+{
+public:
+ CGUIFadeLabelControl(int parentID, int controlID, float posX, float posY, float width, float height, const CLabelInfo& labelInfo, bool scrollOut, int scrollSpeed, DWORD timeToDelayAtEnd, bool resetOnLabelChange);
+ CGUIFadeLabelControl(const CGUIFadeLabelControl &from);
+ virtual ~CGUIFadeLabelControl(void);
+ virtual CGUIFadeLabelControl *Clone() const { return new CGUIFadeLabelControl(*this); };
+
+ virtual void DoRender(DWORD currentTime);
+ virtual void Render();
+ virtual bool CanFocus() const;
+ virtual bool OnMessage(CGUIMessage& message);
+
+ void SetInfo(const std::vector<CGUIInfoLabel> &vecInfo);
+
+protected:
+ virtual void UpdateColors();
+ void AddLabel(const std::string &label);
+
+ std::vector< CGUIInfoLabel > m_infoLabels;
+ unsigned int m_currentLabel;
+ unsigned int m_lastLabel;
+
+ CLabelInfo m_label;
+
+ bool m_scrollOut; // true if we scroll the text all the way to the left before fading in the next label
+ bool m_shortText; // true if the text we have is shorter than the width of the control
+
+ CScrollInfo m_scrollInfo;
+ CGUITextLayout m_textLayout;
+ CAnimation *m_fadeAnim;
+ DWORD m_renderTime;
+ unsigned int m_scrollSpeed;
+ bool m_resetOnLabelChange;
+};
+#endif
diff --git a/guilib/GUIFixedListContainer.cpp b/guilib/GUIFixedListContainer.cpp
new file mode 100644
index 0000000000..aa14f94c2d
--- /dev/null
+++ b/guilib/GUIFixedListContainer.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIFixedListContainer.h"
+#include "GUIListItem.h"
+#include "utils/GUIInfoManager.h"
+#include "Key.h"
+
+CGUIFixedListContainer::CGUIFixedListContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, int scrollTime, int preloadItems, int fixedPosition)
+ : CGUIBaseContainer(parentID, controlID, posX, posY, width, height, orientation, scrollTime, preloadItems)
+{
+ ControlType = GUICONTAINER_FIXEDLIST;
+ m_type = VIEW_TYPE_LIST;
+ m_cursor = fixedPosition;
+}
+
+CGUIFixedListContainer::~CGUIFixedListContainer(void)
+{
+}
+
+bool CGUIFixedListContainer::OnAction(const CAction &action)
+{
+ switch (action.id)
+ {
+ case ACTION_PAGE_UP:
+ {
+ if (m_offset + m_cursor < m_itemsPerPage)
+ { // already on the first page, so move to the first item
+ Scroll(m_offset + m_cursor - m_itemsPerPage);
+ }
+ else
+ { // scroll up to the previous page
+ Scroll(-m_itemsPerPage);
+ }
+ return true;
+ }
+ break;
+ case ACTION_PAGE_DOWN:
+ {
+ if (m_offset + m_cursor >= (int)m_items.size() || (int)m_items.size() < m_itemsPerPage)
+ { // already at the last page, so move to the last item.
+ Scroll(m_items.size() - 1 - m_offset + m_cursor);
+ }
+ else
+ { // scroll down to the next page
+ Scroll(m_itemsPerPage);
+ }
+ return true;
+ }
+ break;
+ // smooth scrolling (for analog controls)
+ case ACTION_SCROLL_UP:
+ {
+ m_analogScrollCount += action.amount1 * action.amount1;
+ bool handled = false;
+ while (m_analogScrollCount > 0.4)
+ {
+ handled = true;
+ m_analogScrollCount -= 0.4f;
+ if (m_offset > -m_cursor)
+ Scroll(-1);
+ }
+ return handled;
+ }
+ break;
+ case ACTION_SCROLL_DOWN:
+ {
+ m_analogScrollCount += action.amount1 * action.amount1;
+ bool handled = false;
+ while (m_analogScrollCount > 0.4)
+ {
+ handled = true;
+ m_analogScrollCount -= 0.4f;
+ if (m_offset < (int)m_items.size() - 1)
+ Scroll(1);
+ }
+ return handled;
+ }
+ break;
+ }
+ return CGUIBaseContainer::OnAction(action);
+}
+
+bool CGUIFixedListContainer::OnMessage(CGUIMessage& message)
+{
+ if (message.GetControlId() == GetID() )
+ {
+ if (message.GetMessage() == GUI_MSG_ITEM_SELECT)
+ {
+ SelectItem(message.GetParam1());
+ return true;
+ }
+ }
+ return CGUIBaseContainer::OnMessage(message);
+}
+
+bool CGUIFixedListContainer::MoveUp(bool wrapAround)
+{
+ if (m_offset > -m_cursor)
+ ScrollToOffset(m_offset - 1);
+ else if (wrapAround)
+ {
+ if (m_items.size() > 0)
+ { // move 2 last item in list
+ int offset = m_items.size() - m_cursor - 1;
+ if (offset < -m_cursor) offset = -m_cursor;
+ ScrollToOffset(offset);
+ g_infoManager.SetContainerMoving(GetID(), -1);
+ }
+ }
+ else
+ return false;
+ return true;
+}
+
+bool CGUIFixedListContainer::MoveDown(bool wrapAround)
+{
+ if (m_offset + m_cursor + 1 < (int)m_items.size())
+ {
+ ScrollToOffset(m_offset + 1);
+ }
+ else if (wrapAround)
+ { // move first item in list
+ ScrollToOffset(-m_cursor);
+ g_infoManager.SetContainerMoving(GetID(), 1);
+ }
+ else
+ return false;
+ return true;
+}
+
+// scrolls the said amount
+void CGUIFixedListContainer::Scroll(int amount)
+{
+ // increase or decrease the offset
+ int offset = m_offset + amount;
+ if (offset >= (int)m_items.size() - m_cursor)
+ {
+ offset = m_items.size() - m_cursor - 1;
+ }
+ if (offset < -m_cursor) offset = -m_cursor;
+ ScrollToOffset(offset);
+}
+
+void CGUIFixedListContainer::ValidateOffset()
+{ // first thing is we check the range of m_offset
+ if (!m_layout) return;
+ if (m_offset > (int)m_items.size() - m_cursor)
+ {
+ m_offset = m_items.size() - m_cursor;
+ m_scrollOffset = m_offset * m_layout->Size(m_orientation);
+ }
+ if (m_offset < -m_cursor)
+ {
+ m_offset = -m_cursor;
+ m_scrollOffset = m_offset * m_layout->Size(m_orientation);
+ }
+}
+
+bool CGUIFixedListContainer::SelectItemFromPoint(const CPoint &point)
+{
+ if (!m_focusedLayout || !m_layout)
+ return false;
+
+ const float mouse_scroll_speed = 0.05f;
+ const float mouse_max_amount = 1.5f; // max speed: 1 item per frame
+ float sizeOfItem = m_layout->Size(m_orientation);
+ // see if the point is either side of our focused item
+ float start = m_cursor * sizeOfItem;
+ float end = start + m_focusedLayout->Size(m_orientation);
+ float pos = (m_orientation == VERTICAL) ? point.y : point.x;
+ if (pos < start - 0.5f * sizeOfItem)
+ { // scroll backward
+ if (!InsideLayout(m_layout, point))
+ return false;
+ float amount = std::min((start - pos) / sizeOfItem, mouse_max_amount);
+ m_analogScrollCount += amount * amount * mouse_scroll_speed;
+ if (m_analogScrollCount > 1)
+ {
+ Scroll(-1);
+ m_analogScrollCount-=1.0f;
+ }
+ return true;
+ }
+ else if (pos > end + 0.5f * sizeOfItem)
+ {
+ if (!InsideLayout(m_layout, point))
+ return false;
+ // scroll forward
+ float amount = std::min((pos - end) / sizeOfItem, mouse_max_amount);
+ m_analogScrollCount += amount * amount * mouse_scroll_speed;
+ if (m_analogScrollCount > 1)
+ {
+ Scroll(1);
+ m_analogScrollCount-=1.0f;
+ }
+ return true;
+ }
+ return InsideLayout(m_focusedLayout, point);
+}
+
+void CGUIFixedListContainer::SelectItem(int item)
+{
+ // Check that m_offset is valid
+ ValidateOffset();
+ // only select an item if it's in a valid range
+ if (item >= 0 && item < (int)m_items.size())
+ {
+ // Select the item requested
+ ScrollToOffset(item - m_cursor);
+ }
+}
+
+bool CGUIFixedListContainer::HasPreviousPage() const
+{
+ return (m_offset > 0);
+}
+
+bool CGUIFixedListContainer::HasNextPage() const
+{
+ return (m_offset != (int)m_items.size() - m_itemsPerPage && (int)m_items.size() >= m_itemsPerPage);
+}
+
+int CGUIFixedListContainer::GetCurrentPage() const
+{
+ int offset = CorrectOffset(m_offset, m_cursor);
+ if (offset + m_itemsPerPage - m_cursor >= (int)GetRows()) // last page
+ return (GetRows() + m_itemsPerPage - 1) / m_itemsPerPage;
+ return offset / m_itemsPerPage + 1;
+}
+
diff --git a/guilib/GUIFixedListContainer.h b/guilib/GUIFixedListContainer.h
new file mode 100644
index 0000000000..f79836bd56
--- /dev/null
+++ b/guilib/GUIFixedListContainer.h
@@ -0,0 +1,56 @@
+/*!
+\file GUIFixedListContainer.h
+\brief
+*/
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIBaseContainer.h"
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIFixedListContainer : public CGUIBaseContainer
+{
+public:
+ CGUIFixedListContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, int scrollTime, int preloadItems, int fixedPosition);
+ virtual ~CGUIFixedListContainer(void);
+ virtual CGUIFixedListContainer *Clone() const { return new CGUIFixedListContainer(*this); };
+
+ virtual bool OnAction(const CAction &action);
+ virtual bool OnMessage(CGUIMessage& message);
+
+protected:
+ virtual void Scroll(int amount);
+ virtual bool MoveDown(bool wrapAround);
+ virtual bool MoveUp(bool wrapAround);
+ virtual void ValidateOffset();
+ virtual bool SelectItemFromPoint(const CPoint &point);
+ virtual void SelectItem(int item);
+ virtual bool HasNextPage() const;
+ virtual bool HasPreviousPage() const;
+ virtual int GetCurrentPage() const;
+};
+
diff --git a/guilib/GUIFont.cpp b/guilib/GUIFont.cpp
new file mode 100644
index 0000000000..d80e3ab39d
--- /dev/null
+++ b/guilib/GUIFont.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIFont.h"
+#include "GUIFontTTF.h"
+#include "GraphicContext.h"
+
+#include "utils/SingleLock.h"
+#include "MathUtils.h"
+
+#define ROUND(x) (float)(MathUtils::round_int(x))
+
+float CScrollInfo::GetPixelsPerFrame()
+{
+ static const float alphaEMA = 0.05f;
+
+ if (0 == pixelSpeed)
+ return 0; // not scrolling
+ DWORD currentTime = timeGetTime();
+ float delta = m_lastFrameTime ? (float)(currentTime - m_lastFrameTime) : m_averageFrameTime;
+ if (delta > 100)
+ delta = 100; // assume a minimum of 10 fps
+ m_lastFrameTime = currentTime;
+ // do an exponential moving average of the frame time
+ m_averageFrameTime = m_averageFrameTime + (delta - m_averageFrameTime) * alphaEMA;
+ // and multiply by pixel speed (per ms) to get number of pixels to move this frame
+ return pixelSpeed * m_averageFrameTime;
+}
+
+CGUIFont::CGUIFont(const CStdString& strFontName, uint32_t style, color_t textColor, color_t shadowColor, float lineSpacing, CGUIFontTTFBase *font)
+{
+ m_strFontName = strFontName;
+ m_style = style & 3;
+ m_textColor = textColor;
+ m_shadowColor = shadowColor;
+ m_lineSpacing = lineSpacing;
+ m_font = font;
+
+ if (m_font)
+ m_font->AddReference();
+}
+
+CGUIFont::~CGUIFont()
+{
+ if (m_font)
+ m_font->RemoveReference();
+}
+
+CStdString& CGUIFont::GetFontName()
+{
+ return m_strFontName;
+}
+
+void CGUIFont::DrawText( float x, float y, const vecColors &colors, color_t shadowColor,
+ const vecText &text, uint32_t alignment, float maxPixelWidth)
+{
+ if (!m_font) return;
+
+ bool clip = maxPixelWidth > 0;
+ if (clip && ClippedRegionIsEmpty(x, y, maxPixelWidth, alignment))
+ return;
+
+ maxPixelWidth = ROUND(maxPixelWidth / g_graphicsContext.GetGUIScaleX());
+ vecColors renderColors;
+ for (unsigned int i = 0; i < colors.size(); i++)
+ renderColors.push_back(g_graphicsContext.MergeAlpha(colors[i] ? colors[i] : m_textColor));
+ if (!shadowColor) shadowColor = m_shadowColor;
+ if (shadowColor)
+ m_font->DrawTextInternal(x + 1, y + 1, g_graphicsContext.MergeAlpha(shadowColor), text, alignment, maxPixelWidth, false);
+ m_font->DrawTextInternal( x, y, renderColors, text, alignment, maxPixelWidth, false);
+
+ if (clip)
+ g_graphicsContext.RestoreClipRegion();
+}
+
+void CGUIFont::DrawScrollingText(float x, float y, const vecColors &colors, color_t shadowColor,
+ const vecText &text, uint32_t alignment, float maxWidth, CScrollInfo &scrollInfo)
+{
+ if (!m_font) return;
+ if (!shadowColor) shadowColor = m_shadowColor;
+
+ float spaceWidth = GetCharWidth(L' ');
+ // max chars on screen + extra margin chars
+ vecText::size_type maxChars =
+ std::min<vecText::size_type>(
+ (text.size() + (vecText::size_type)scrollInfo.suffix.size()),
+ (vecText::size_type)((maxWidth * 1.05f) / spaceWidth));
+
+ if (!text.size() || ClippedRegionIsEmpty(x, y, maxWidth, alignment))
+ return; // nothing to render
+
+ maxWidth = ROUND(maxWidth / g_graphicsContext.GetGUIScaleX());
+
+ // draw at our scroll position
+ // we handle the scrolling as follows:
+ // We scroll on a per-pixel basis up until we have scrolled the first character outside
+ // of our viewport, whereby we cycle the string around, and reset the scroll position.
+ //
+ // pixelPos is the amount in pixels to move the string by.
+ // characterPos is the amount in characters to rotate the string by.
+ //
+ float offset = scrollInfo.pixelPos;
+ if (!scrollInfo.waitTime)
+ {
+ // move along by the appropriate scroll amount
+ float scrollAmount = fabs(scrollInfo.GetPixelsPerFrame() * g_graphicsContext.GetGUIScaleX());
+
+ if (scrollInfo.pixelSpeed > 0)
+ {
+ // we want to move scrollAmount, grab the next character
+ float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
+ if (scrollInfo.pixelPos + scrollAmount < charWidth)
+ scrollInfo.pixelPos += scrollAmount; // within the current character
+ else
+ { // past the current character, decrement scrollAmount by the charWidth and move to the next character
+ while (scrollInfo.pixelPos + scrollAmount >= charWidth)
+ {
+ scrollAmount -= (charWidth - scrollInfo.pixelPos);
+ scrollInfo.pixelPos = 0;
+ scrollInfo.characterPos++;
+ if (scrollInfo.characterPos >= text.size() + scrollInfo.suffix.size())
+ {
+ scrollInfo.Reset();
+ break;
+ }
+ charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
+ }
+ }
+ offset = scrollInfo.pixelPos;
+ }
+ else if (scrollInfo.pixelSpeed < 0)
+ { // scrolling backwards
+ // we want to move scrollAmount, grab the next character
+ float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
+ if (scrollInfo.pixelPos + scrollAmount < charWidth)
+ scrollInfo.pixelPos += scrollAmount; // within the current character
+ else
+ { // past the current character, decrement scrollAmount by the charWidth and move to the next character
+ while (scrollInfo.pixelPos + scrollAmount >= charWidth)
+ {
+ scrollAmount -= (charWidth - scrollInfo.pixelPos);
+ scrollInfo.pixelPos = 0;
+ if (scrollInfo.characterPos == 0)
+ {
+ scrollInfo.Reset();
+ scrollInfo.characterPos = text.size() + scrollInfo.suffix.size() - 1;
+ break;
+ }
+ scrollInfo.characterPos--;
+ charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
+ }
+ }
+ offset = charWidth - scrollInfo.pixelPos;
+ }
+ }
+ else
+ scrollInfo.waitTime--;
+
+ // Now rotate our string as needed, only take a slightly larger then visible part of the text.
+ unsigned int pos = scrollInfo.characterPos;
+ vecText renderText;
+ renderText.reserve(maxChars);
+ for (vecText::size_type i = 0; i < maxChars; i++)
+ {
+ if (pos >= text.size() + scrollInfo.suffix.size())
+ pos = 0;
+ if (pos < text.size())
+ renderText.push_back(text[pos]);
+ else
+ renderText.push_back(scrollInfo.suffix[pos - text.size()]);
+ pos++;
+ }
+
+ vecColors renderColors;
+ for (unsigned int i = 0; i < colors.size(); i++)
+ renderColors.push_back(g_graphicsContext.MergeAlpha(colors[i] ? colors[i] : m_textColor));
+
+ bool scroll = !scrollInfo.waitTime && scrollInfo.pixelSpeed;
+ if (shadowColor)
+ m_font->DrawTextInternal(x - offset + 1, y + 1, g_graphicsContext.MergeAlpha(shadowColor), renderText, alignment, maxWidth + scrollInfo.pixelPos + m_font->GetLineHeight(2.0f), scroll);
+
+ m_font->DrawTextInternal(x - offset, y, renderColors, renderText, alignment, maxWidth + scrollInfo.pixelPos + m_font->GetLineHeight(2.0f), scroll);
+
+ g_graphicsContext.RestoreClipRegion();
+}
+
+// remaps unsupported font glpyhs to other suitable ones
+wchar_t CGUIFont::RemapGlyph(wchar_t letter)
+{
+ if (letter == 0x2019 || letter == 0x2018) return 0x0027; // single quotes
+ else if (letter == 0x201c || letter == 0x201d) return 0x0022;
+ return 0; // no decent character map
+}
+
+bool CGUIFont::ClippedRegionIsEmpty(float x, float y, float width, uint32_t alignment) const
+{
+ if (alignment & XBFONT_CENTER_X)
+ x -= width * 0.5f;
+ else if (alignment & XBFONT_RIGHT)
+ x -= width;
+ if (alignment & XBFONT_CENTER_Y)
+ y -= m_font->GetLineHeight(m_lineSpacing);
+
+ return !g_graphicsContext.SetClipRegion(x, y, width, m_font->GetLineHeight(2.0f) * g_graphicsContext.GetGUIScaleY());
+}
+
+float CGUIFont::GetTextWidth( const vecText &text )
+{
+ if (!m_font) return 0;
+ CSingleLock lock(g_graphicsContext);
+ return m_font->GetTextWidthInternal(text.begin(), text.end()) * g_graphicsContext.GetGUIScaleX();
+}
+
+float CGUIFont::GetCharWidth( character_t ch )
+{
+ if (!m_font) return 0;
+ CSingleLock lock(g_graphicsContext);
+ return m_font->GetCharWidthInternal(ch) * g_graphicsContext.GetGUIScaleX();
+}
+
+float CGUIFont::GetTextHeight(int numLines) const
+{
+ if (!m_font) return 0;
+ return m_font->GetTextHeight(m_lineSpacing, numLines) * g_graphicsContext.GetGUIScaleY();
+}
+
+float CGUIFont::GetLineHeight() const
+{
+ if (!m_font) return 0;
+ return m_font->GetLineHeight(m_lineSpacing) * g_graphicsContext.GetGUIScaleY();
+}
+
+void CGUIFont::Begin()
+{
+ if (!m_font) return;
+ m_font->Begin();
+}
+
+void CGUIFont::End()
+{
+ if (!m_font) return;
+ m_font->End();
+}
+
+void CGUIFont::SetFont(CGUIFontTTFBase *font)
+{
+ if (m_font == font)
+ return; // no need to update the font if we already have it
+ if (m_font)
+ m_font->RemoveReference();
+ m_font = font;
+ if (m_font)
+ m_font->AddReference();
+}
diff --git a/guilib/GUIFont.h b/guilib/GUIFont.h
new file mode 100644
index 0000000000..88d996053f
--- /dev/null
+++ b/guilib/GUIFont.h
@@ -0,0 +1,142 @@
+/*!
+\file GUIFont.h
+\brief
+*/
+
+#ifndef CGUILIB_GUIFONT_H
+#define CGUILIB_GUIFONT_H
+#pragma once
+
+#include "StdString.h"
+#include <assert.h>
+
+typedef uint32_t character_t;
+typedef uint32_t color_t;
+typedef std::vector<character_t> vecText;
+typedef std::vector<color_t> vecColors;
+
+class CGUIFontTTFBase;
+
+// flags for alignment
+#define XBFONT_LEFT 0x00000000
+#define XBFONT_RIGHT 0x00000001
+#define XBFONT_CENTER_X 0x00000002
+#define XBFONT_CENTER_Y 0x00000004
+#define XBFONT_TRUNCATED 0x00000008
+#define XBFONT_JUSTIFIED 0x00000010
+
+#define FONT_STYLE_NORMAL 0
+#define FONT_STYLE_BOLD 1
+#define FONT_STYLE_ITALICS 2
+#define FONT_STYLE_BOLD_ITALICS 3
+
+class CScrollInfo
+{
+public:
+ CScrollInfo(unsigned int wait = 50, float pos = 0, int speed = defaultSpeed, const CStdStringW &scrollSuffix = L" | ")
+ {
+ initialWait = wait;
+ initialPos = pos;
+ SetSpeed(speed);
+ suffix = scrollSuffix;
+ Reset();
+ };
+ void SetSpeed(int speed)
+ {
+ pixelSpeed = speed * 0.001f;
+ }
+ void Reset()
+ {
+ waitTime = initialWait;
+ characterPos = 0;
+ // pixelPos is where we start the current letter, so is measured
+ // to the left of the text rendering's left edge. Thus, a negative
+ // value will mean the text starts to the right
+ pixelPos = -initialPos;
+ // privates:
+ m_averageFrameTime = 1000.f / abs(defaultSpeed);
+ m_lastFrameTime = 0;
+ }
+ uint32_t GetCurrentChar(const vecText &text) const
+ {
+ assert(text.size());
+ if (characterPos < text.size())
+ return text[characterPos];
+ else if (characterPos < text.size() + suffix.size())
+ return suffix[characterPos - text.size()];
+ return text[0];
+ }
+ float GetPixelsPerFrame();
+
+ float pixelPos;
+ float pixelSpeed;
+ unsigned int waitTime;
+ unsigned int characterPos;
+ unsigned int initialWait;
+ float initialPos;
+ CStdStringW suffix;
+
+ static const int defaultSpeed = 60;
+private:
+ float m_averageFrameTime;
+ uint32_t m_lastFrameTime;
+};
+
+/*!
+ \ingroup textures
+ \brief
+ */
+class CGUIFont
+{
+public:
+ CGUIFont(const CStdString& strFontName, uint32_t style, color_t textColor, color_t shadowColor, float lineSpacing, CGUIFontTTFBase *font);
+ virtual ~CGUIFont();
+
+ CStdString& GetFontName();
+
+ void DrawText( float x, float y, color_t color, color_t shadowColor,
+ const vecText &text, uint32_t alignment, float maxPixelWidth)
+ {
+ vecColors colors;
+ colors.push_back(color);
+ DrawText(x, y, colors, shadowColor, text, alignment, maxPixelWidth);
+ };
+
+ void DrawText( float x, float y, const vecColors &colors, color_t shadowColor,
+ const vecText &text, uint32_t alignment, float maxPixelWidth);
+
+ void DrawScrollingText( float x, float y, const vecColors &colors, color_t shadowColor,
+ const vecText &text, uint32_t alignment, float maxPixelWidth, CScrollInfo &scrollInfo);
+
+ float GetTextWidth( const vecText &text );
+ float GetCharWidth( character_t ch );
+ float GetTextHeight(int numLines) const;
+ float GetLineHeight() const;
+
+ void Begin();
+ void End();
+
+ uint32_t GetStyle() const { return m_style; };
+
+ static wchar_t RemapGlyph(wchar_t letter);
+
+ CGUIFontTTFBase* GetFont() const
+ {
+ return m_font;
+ }
+
+ void SetFont(CGUIFontTTFBase* font);
+
+protected:
+ CStdString m_strFontName;
+ uint32_t m_style;
+ color_t m_shadowColor;
+ color_t m_textColor;
+ float m_lineSpacing;
+ CGUIFontTTFBase *m_font; // the font object has the size information
+
+private:
+ bool ClippedRegionIsEmpty(float x, float y, float width, uint32_t alignment) const;
+};
+
+#endif
diff --git a/guilib/GUIFontManager.cpp b/guilib/GUIFontManager.cpp
new file mode 100644
index 0000000000..6a011daf84
--- /dev/null
+++ b/guilib/GUIFontManager.cpp
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIFontManager.h"
+#include "GraphicContext.h"
+#include "SkinInfo.h"
+#include "GUIFontTTF.h"
+#include "GUIFont.h"
+#include "XMLUtils.h"
+#include "GUIControlFactory.h"
+#include "../xbmc/Util.h"
+#include "../xbmc/FileSystem/File.h"
+#include "../xbmc/FileSystem/SpecialProtocol.h"
+#include "utils/log.h"
+#include "WindowingFactory.h"
+
+using namespace std;
+
+GUIFontManager g_fontManager;
+
+GUIFontManager::GUIFontManager(void)
+{
+ m_skinResolution=RES_INVALID;
+ m_fontsetUnicode=false;
+ m_bFontsNeedReloading = false;
+}
+
+GUIFontManager::~GUIFontManager(void)
+{
+ Clear();
+}
+
+CGUIFont* GUIFontManager::LoadTTF(const CStdString& strFontName, const CStdString& strFilename, color_t textColor, color_t shadowColor, const int iSize, const int iStyle, float lineSpacing, float aspect, RESOLUTION sourceRes)
+{
+ float originalAspect = aspect;
+
+ //check if font already exists
+ CGUIFont* pFont = GetFont(strFontName, false);
+ if (pFont)
+ return pFont;
+
+ if (sourceRes == RES_INVALID) // no source res specified, so assume the skin res
+ sourceRes = m_skinResolution;
+
+
+ // set scaling resolution so that we can scale our font sizes correctly
+ // as fonts aren't scaled at render time (due to aliasing) we must scale
+ // the size of the fonts before they are drawn to bitmaps
+ g_graphicsContext.SetScalingResolution(sourceRes, 0, 0, true);
+
+ // adjust aspect ratio
+ if (sourceRes == RES_PAL_16x9 || sourceRes == RES_PAL60_16x9 || sourceRes == RES_NTSC_16x9 || sourceRes == RES_HDTV_480p_16x9)
+ aspect *= 0.75f;
+
+ aspect *= g_graphicsContext.GetGUIScaleY() / g_graphicsContext.GetGUIScaleX();
+ float newSize = (float) iSize / g_graphicsContext.GetGUIScaleY();
+
+ // First try to load the font from the skin
+ CStdString strPath;
+ if (!CURL::IsFullPath(strFilename))
+ {
+ strPath = CUtil::AddFileToFolder(g_graphicsContext.GetMediaDir(), "fonts");
+ strPath = CUtil::AddFileToFolder(strPath, strFilename);
+ }
+ else
+ strPath = strFilename;
+
+#ifdef _LINUX
+ strPath = PTH_IC(strPath);
+#endif
+
+ // Check if the file exists, otherwise try loading it from the global media dir
+ if (!XFILE::CFile::Exists(strPath))
+ {
+ strPath = CUtil::AddFileToFolder("special://xbmc/media/Fonts", CUtil::GetFileName(strFilename));
+#ifdef _LINUX
+ strPath = PTH_IC(strPath);
+#endif
+ }
+
+ // check if we already have this font file loaded (font object could differ only by color or style)
+ CStdString TTFfontName;
+ TTFfontName.Format("%s_%f_%f", strFilename, newSize, aspect);
+
+ CGUIFontTTFBase* pFontFile = GetFontFile(TTFfontName);
+ if (!pFontFile)
+ {
+ pFontFile = new CGUIFontTTF(TTFfontName);
+ bool bFontLoaded = pFontFile->Load(strPath, newSize, aspect);
+
+ if (!bFontLoaded)
+ {
+ delete pFontFile;
+
+ // font could not be loaded - try Arial.ttf, which we distribute
+ if (strFilename != "arial.ttf")
+ {
+ CLog::Log(LOGERROR, "Couldn't load font name: %s(%s), trying to substitute arial.ttf", strFontName.c_str(), strFilename.c_str());
+ return LoadTTF(strFontName, "arial.ttf", textColor, shadowColor, iSize, iStyle, lineSpacing, originalAspect);
+ }
+ CLog::Log(LOGERROR, "Couldn't load font name:%s file:%s", strFontName.c_str(), strPath.c_str());
+
+ return NULL;
+ }
+
+ m_vecFontFiles.push_back(pFontFile);
+ }
+
+ // font file is loaded, create our CGUIFont
+ CGUIFont *pNewFont = new CGUIFont(strFontName, iStyle, textColor, shadowColor, lineSpacing, pFontFile);
+ m_vecFonts.push_back(pNewFont);
+
+ // Store the original TTF font info in case we need to reload it in a different resolution
+ OrigFontInfo fontInfo;
+ fontInfo.size = iSize;
+ fontInfo.aspect = originalAspect;
+ fontInfo.fontFilePath = strPath;
+ fontInfo.fileName = strFilename;
+ m_vecFontInfo.push_back(fontInfo);
+
+ return pNewFont;
+}
+
+void GUIFontManager::ReloadTTFFonts(void)
+{
+ if (!m_vecFonts.size())
+ return; // we haven't even loaded fonts in yet
+
+ // check if the device is ready
+ if(g_Windowing.GetDeviceStatus() != S_OK)
+ {
+ m_bFontsNeedReloading = true;
+ return;
+ }
+
+ g_graphicsContext.SetScalingResolution(m_skinResolution, 0, 0, true);
+
+ for (unsigned int i = 0; i < m_vecFonts.size(); i++)
+ {
+ CGUIFont* font = m_vecFonts[i];
+ OrigFontInfo fontInfo = m_vecFontInfo[i];
+
+ float aspect = fontInfo.aspect;
+ int iSize = fontInfo.size;
+ CStdString& strPath = fontInfo.fontFilePath;
+ CStdString& strFilename = fontInfo.fileName;
+
+ if (m_skinResolution == RES_PAL_16x9 || m_skinResolution == RES_PAL60_16x9 || m_skinResolution == RES_NTSC_16x9 || m_skinResolution == RES_HDTV_480p_16x9)
+ aspect *= 0.75f;
+
+ aspect *= g_graphicsContext.GetGUIScaleY() / g_graphicsContext.GetGUIScaleX();
+ float newSize = (float) iSize / g_graphicsContext.GetGUIScaleY();
+
+ CStdString TTFfontName;
+ TTFfontName.Format("%s_%f_%f", strFilename, newSize, aspect);
+ CGUIFontTTFBase* pFontFile = GetFontFile(TTFfontName);
+ if (!pFontFile)
+ {
+ pFontFile = new CGUIFontTTF(TTFfontName);
+ if (!pFontFile || !pFontFile->Load(strPath, newSize, aspect))
+ {
+ delete pFontFile;
+ // font could not be loaded
+ CLog::Log(LOGERROR, "Couldn't re-load font file:%s", strPath.c_str());
+ return;
+ }
+
+ m_vecFontFiles.push_back(pFontFile);
+ }
+
+ font->SetFont(pFontFile);
+ }
+
+ m_bFontsNeedReloading = false;
+ // send a message to our controls telling them they need to refresh.
+ g_graphicsContext.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_INVALIDATE);
+}
+
+void GUIFontManager::Unload(const CStdString& strFontName)
+{
+ for (vector<CGUIFont*>::iterator iFont = m_vecFonts.begin(); iFont != m_vecFonts.end(); ++iFont)
+ {
+ if ((*iFont)->GetFontName() == strFontName)
+ {
+ delete (*iFont);
+ m_vecFonts.erase(iFont);
+ return;
+ }
+ }
+}
+
+void GUIFontManager::FreeFontFile(CGUIFontTTFBase *pFont)
+{
+ for (vector<CGUIFontTTFBase*>::iterator it = m_vecFontFiles.begin(); it != m_vecFontFiles.end(); ++it)
+ {
+ if (pFont == *it)
+ {
+ m_vecFontFiles.erase(it);
+ delete pFont;
+ return;
+ }
+ }
+}
+
+CGUIFontTTFBase* GUIFontManager::GetFontFile(const CStdString& strFileName)
+{
+ for (int i = 0; i < (int)m_vecFontFiles.size(); ++i)
+ {
+ CGUIFontTTFBase* pFont = (CGUIFontTTFBase *)m_vecFontFiles[i];
+ if (pFont->GetFileName() == strFileName)
+ return pFont;
+ }
+ return NULL;
+}
+
+CGUIFont* GUIFontManager::GetFont(const CStdString& strFontName, bool fallback /*= true*/)
+{
+ for (int i = 0; i < (int)m_vecFonts.size(); ++i)
+ {
+ CGUIFont* pFont = m_vecFonts[i];
+ if (pFont->GetFontName() == strFontName)
+ return pFont;
+ }
+ // fall back to "font13" if we have none
+ if (fallback && !strFontName.IsEmpty() && !strFontName.Equals("-") && !strFontName.Equals("font13"))
+ return GetFont("font13");
+ return NULL;
+}
+
+void GUIFontManager::Clear()
+{
+ for (int i = 0; i < (int)m_vecFonts.size(); ++i)
+ {
+ CGUIFont* pFont = m_vecFonts[i];
+ delete pFont;
+ }
+
+ m_vecFonts.clear();
+ m_vecFontFiles.clear();
+ m_vecFontInfo.clear();
+ m_fontsetUnicode=false;
+}
+
+void GUIFontManager::LoadFonts(const CStdString& strFontSet)
+{
+ TiXmlDocument xmlDoc;
+ if (!OpenFontFile(xmlDoc))
+ return;
+
+ TiXmlElement* pRootElement = xmlDoc.RootElement();
+ const TiXmlNode *pChild = pRootElement->FirstChild();
+
+ // If there are no fontset's defined in the XML (old skin format) run in backward compatibility
+ // and ignore the fontset request
+ CStdString strValue = pChild->Value();
+ if (strValue == "fontset")
+ {
+ CStdString foundTTF;
+ while (pChild)
+ {
+ strValue = pChild->Value();
+ if (strValue == "fontset")
+ {
+ const char* idAttr = ((TiXmlElement*) pChild)->Attribute("id");
+
+ const char* unicodeAttr = ((TiXmlElement*) pChild)->Attribute("unicode");
+
+ if (foundTTF.IsEmpty() && idAttr != NULL && unicodeAttr != NULL && stricmp(unicodeAttr, "true") == 0)
+ foundTTF = idAttr;
+
+ // Check if this is the fontset that we want
+ if (idAttr != NULL && stricmp(strFontSet.c_str(), idAttr) == 0)
+ {
+ m_fontsetUnicode=false;
+ // Check if this is the a ttf fontset
+ if (unicodeAttr != NULL && stricmp(unicodeAttr, "true") == 0)
+ m_fontsetUnicode=true;
+
+ if (m_fontsetUnicode)
+ {
+ LoadFonts(pChild->FirstChild());
+ break;
+ }
+ }
+
+ }
+
+ pChild = pChild->NextSibling();
+ }
+
+ // If no fontset was loaded
+ if (pChild == NULL)
+ {
+ CLog::Log(LOGWARNING, "file doesnt have <fontset> with name '%s', defaulting to first fontset", strFontSet.c_str());
+ if (!foundTTF.IsEmpty())
+ LoadFonts(foundTTF);
+ }
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "file doesnt have <fontset> in <fonts>, but rather %s", strValue.c_str());
+ return ;
+ }
+}
+
+void GUIFontManager::LoadFonts(const TiXmlNode* fontNode)
+{
+ while (fontNode)
+ {
+ CStdString strValue = fontNode->Value();
+ if (strValue == "font")
+ {
+ const TiXmlNode *pNode = fontNode->FirstChild("name");
+ if (pNode)
+ {
+ CStdString strFontName = pNode->FirstChild()->Value();
+ color_t shadowColor = 0;
+ color_t textColor = 0;
+ CGUIControlFactory::GetColor(fontNode, "shadow", shadowColor);
+ CGUIControlFactory::GetColor(fontNode, "color", textColor);
+ const TiXmlNode *pNode = fontNode->FirstChild("filename");
+ if (pNode)
+ {
+ CStdString strFontFileName = pNode->FirstChild()->Value();
+ if (strFontFileName.Find(".ttf") >= 0)
+ {
+ int iSize = 20;
+ int iStyle = FONT_STYLE_NORMAL;
+ float aspect = 1.0f;
+ float lineSpacing = 1.0f;
+
+ XMLUtils::GetInt(fontNode, "size", iSize);
+ if (iSize <= 0) iSize = 20;
+
+ pNode = fontNode->FirstChild("style");
+ if (pNode)
+ {
+ CStdString style = pNode->FirstChild()->Value();
+ iStyle = FONT_STYLE_NORMAL;
+ if (style == "bold")
+ iStyle = FONT_STYLE_BOLD;
+ else if (style == "italics")
+ iStyle = FONT_STYLE_ITALICS;
+ else if (style == "bolditalics")
+ iStyle = FONT_STYLE_BOLD_ITALICS;
+ }
+
+ XMLUtils::GetFloat(fontNode, "linespacing", lineSpacing);
+ XMLUtils::GetFloat(fontNode, "aspect", aspect);
+
+ LoadTTF(strFontName, strFontFileName, textColor, shadowColor, iSize, iStyle, lineSpacing, aspect);
+ }
+ }
+ }
+ }
+
+ fontNode = fontNode->NextSibling();
+ }
+}
+
+bool GUIFontManager::OpenFontFile(TiXmlDocument& xmlDoc)
+{
+ // Get the file to load fonts from:
+ CStdString strPath = g_SkinInfo.GetSkinPath("Font.xml", &m_skinResolution);
+ CLog::Log(LOGINFO, "Loading fonts from %s", strPath.c_str());
+
+ // first try our preferred file
+ if ( !xmlDoc.LoadFile(strPath) )
+ {
+ CLog::Log(LOGERROR, "Couldn't load %s", strPath.c_str());
+ return false;
+ }
+ TiXmlElement* pRootElement = xmlDoc.RootElement();
+
+ CStdString strValue = pRootElement->Value();
+ if (strValue != CStdString("fonts"))
+ {
+ CLog::Log(LOGERROR, "file %s doesnt start with <fonts>", strPath.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+bool GUIFontManager::GetFirstFontSetUnicode(CStdString& strFontSet)
+{
+ strFontSet.Empty();
+
+ // Load our font file
+ TiXmlDocument xmlDoc;
+ if (!OpenFontFile(xmlDoc))
+ return false;
+
+ TiXmlElement* pRootElement = xmlDoc.RootElement();
+ const TiXmlNode *pChild = pRootElement->FirstChild();
+
+ CStdString strValue = pChild->Value();
+ if (strValue == "fontset")
+ {
+ while (pChild)
+ {
+ strValue = pChild->Value();
+ if (strValue == "fontset")
+ {
+ const char* idAttr = ((TiXmlElement*) pChild)->Attribute("id");
+
+ const char* unicodeAttr = ((TiXmlElement*) pChild)->Attribute("unicode");
+
+ // Check if this is a fontset with a ttf attribute set to true
+ if (unicodeAttr != NULL && stricmp(unicodeAttr, "true") == 0)
+ {
+ // This is the first ttf fontset
+ strFontSet=idAttr;
+ break;
+ }
+
+ }
+
+ pChild = pChild->NextSibling();
+ }
+
+ // If no fontset was loaded
+ if (pChild == NULL)
+ CLog::Log(LOGWARNING, "file doesnt have <fontset> with with attibute unicode=\"true\"");
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "file doesnt have <fontset> in <fonts>, but rather %s", strValue.c_str());
+ }
+
+ return !strFontSet.IsEmpty();
+}
+
+bool GUIFontManager::IsFontSetUnicode(const CStdString& strFontSet)
+{
+ TiXmlDocument xmlDoc;
+ if (!OpenFontFile(xmlDoc))
+ return false;
+
+ TiXmlElement* pRootElement = xmlDoc.RootElement();
+ const TiXmlNode *pChild = pRootElement->FirstChild();
+
+ CStdString strValue = pChild->Value();
+ if (strValue == "fontset")
+ {
+ while (pChild)
+ {
+ strValue = pChild->Value();
+ if (strValue == "fontset")
+ {
+ const char* idAttr = ((TiXmlElement*) pChild)->Attribute("id");
+
+ const char* unicodeAttr = ((TiXmlElement*) pChild)->Attribute("unicode");
+
+ // Check if this is the fontset that we want
+ if (idAttr != NULL && stricmp(strFontSet.c_str(), idAttr) == 0)
+ return (unicodeAttr != NULL && stricmp(unicodeAttr, "true") == 0);
+
+ }
+
+ pChild = pChild->NextSibling();
+ }
+ }
+
+ return false;
+}
diff --git a/guilib/GUIFontManager.h b/guilib/GUIFontManager.h
new file mode 100644
index 0000000000..9c4e847883
--- /dev/null
+++ b/guilib/GUIFontManager.h
@@ -0,0 +1,89 @@
+/*!
+\file GUIFontManager.h
+\brief
+*/
+
+#ifndef GUILIB_FONTMANAGER_H
+#define GUILIB_FONTMANAGER_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GraphicContext.h"
+
+// Forward
+class CGUIFont;
+class CGUIFontTTFBase;
+class TiXmlDocument;
+class TiXmlNode;
+
+struct OrigFontInfo
+{
+ int size;
+ float aspect;
+ CStdString fontFilePath;
+ CStdString fileName;
+};
+
+/*!
+ \ingroup textures
+ \brief
+ */
+class GUIFontManager
+{
+public:
+ GUIFontManager(void);
+ virtual ~GUIFontManager(void);
+ void Unload(const CStdString& strFontName);
+ void LoadFonts(const CStdString& strFontSet);
+ CGUIFont* LoadTTF(const CStdString& strFontName, const CStdString& strFilename, color_t textColor, color_t shadowColor, const int iSize, const int iStyle, float lineSpacing = 1.0f, float aspect = 1.0f, RESOLUTION res = RES_INVALID);
+ CGUIFont* GetFont(const CStdString& strFontName, bool fallback = true);
+ void Clear();
+ void FreeFontFile(CGUIFontTTFBase *pFont);
+
+ bool IsFontSetUnicode() { return m_fontsetUnicode; }
+ bool IsFontSetUnicode(const CStdString& strFontSet);
+ bool GetFirstFontSetUnicode(CStdString& strFontSet);
+ bool FontsNeedReloading() { return m_bFontsNeedReloading; }
+
+ void ReloadTTFFonts(void);
+
+protected:
+ void LoadFonts(const TiXmlNode* fontNode);
+ CGUIFontTTFBase* GetFontFile(const CStdString& strFontFile);
+ bool OpenFontFile(TiXmlDocument& xmlDoc);
+
+ std::vector<CGUIFont*> m_vecFonts;
+ std::vector<CGUIFontTTFBase*> m_vecFontFiles;
+ std::vector<OrigFontInfo> m_vecFontInfo;
+ bool m_fontsetUnicode;
+ RESOLUTION m_skinResolution;
+ bool m_bFontsNeedReloading;
+};
+
+/*!
+ \ingroup textures
+ \brief
+ */
+extern GUIFontManager g_fontManager;
+#endif
diff --git a/guilib/GUIFontTTF.cpp b/guilib/GUIFontTTF.cpp
new file mode 100644
index 0000000000..91dd551bcf
--- /dev/null
+++ b/guilib/GUIFontTTF.cpp
@@ -0,0 +1,772 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIFont.h"
+#include "GUIFontTTF.h"
+#include "GUIFontManager.h"
+#include "Texture.h"
+#include "GraphicContext.h"
+#include "FileSystem/SpecialProtocol.h"
+#include "MathUtils.h"
+#include "utils/log.h"
+
+#include <math.h>
+
+// stuff for freetype
+#ifndef _LINUX
+#include "ft2build.h"
+#else
+#include <ft2build.h>
+#endif
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+
+#define USE_RELEASE_LIBS
+
+using namespace std;
+
+
+
+// our free type library (debug)
+#if defined(_DEBUG) && !defined(USE_RELEASE_LIBS)
+ #pragma comment (lib,"../../guilib/freetype2/freetype239ST_D.lib")
+#elif !defined(__GNUC__)
+ #pragma comment (lib,"../../guilib/freetype2/freetype239ST.lib")
+#endif
+
+
+#define CHARS_PER_TEXTURE_LINE 20 // number of characters to cache per texture line
+#define CHAR_CHUNK 64 // 64 chars allocated at a time (1024 bytes)
+
+int CGUIFontTTFBase::justification_word_weight = 6; // weight of word spacing over letter spacing when justifying.
+ // A larger number means more of the "dead space" is placed between
+ // words rather than between letters.
+
+unsigned int CGUIFontTTFBase::max_texture_size = 2048; // max texture size - 2048 for GMA965
+
+class CFreeTypeLibrary
+{
+public:
+ CFreeTypeLibrary()
+ {
+ m_library = NULL;
+ }
+
+ virtual ~CFreeTypeLibrary()
+ {
+ if (m_library)
+ FT_Done_FreeType(m_library);
+ }
+
+ FT_Face GetFont(const CStdString &filename, float size, float aspect)
+ {
+ // don't have it yet - create it
+ if (!m_library)
+ FT_Init_FreeType(&m_library);
+ if (!m_library)
+ {
+ CLog::Log(LOGERROR, "Unable to initialize freetype library");
+ return NULL;
+ }
+
+ FT_Face face;
+
+ // ok, now load the font face
+ if (FT_New_Face( m_library, _P(filename).c_str(), 0, &face ))
+ return NULL;
+
+ unsigned int ydpi = GetDPI();
+ unsigned int xdpi = (unsigned int)MathUtils::round_int(ydpi * aspect);
+
+ // we set our screen res currently to 96dpi in both directions (windows default)
+ // we cache our characters (for rendering speed) so it's probably
+ // not a good idea to allow free scaling of fonts - rather, just
+ // scaling to pixel ratio on screen perhaps?
+ if (FT_Set_Char_Size( face, 0, (int)(size*64 + 0.5f), xdpi, ydpi ))
+ {
+ FT_Done_Face(face);
+ return NULL;
+ }
+
+ return face;
+ };
+
+ void ReleaseFont(FT_Face face)
+ {
+ assert(face);
+ FT_Done_Face(face);
+ };
+
+ unsigned int GetDPI() const
+ {
+ return 72; // default dpi, matches what XPR fonts used to use for sizing
+ };
+
+private:
+ FT_Library m_library;
+};
+
+CFreeTypeLibrary g_freeTypeLibrary; // our freetype library
+
+CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName)
+{
+ m_texture = NULL;
+ m_char = NULL;
+ m_maxChars = 0;
+ m_nestedBeginCount = 0;
+
+ m_bTextureLoaded = false;
+ m_vertex_size = 4*1024;
+ m_vertex = (SVertex*)malloc(m_vertex_size * sizeof(SVertex));
+
+ m_face = NULL;
+ memset(m_charquick, 0, sizeof(m_charquick));
+ m_strFileName = strFileName;
+ m_referenceCount = 0;
+ m_originX = m_originY = 0.0f;
+ m_cellBaseLine = m_cellHeight = 0;
+ m_numChars = 0;
+ m_posX = m_posY = 0;
+ m_textureHeight = m_textureWidth = 0;
+ m_textureScaleX = m_textureScaleY = 0.0;
+ m_ellipsesWidth = m_height = 0.0f;
+ m_color = 0;
+ m_vertex_count = 0;
+ m_nTexture = 0;
+}
+
+CGUIFontTTFBase::~CGUIFontTTFBase(void)
+{
+ Clear();
+}
+
+void CGUIFontTTFBase::AddReference()
+{
+ m_referenceCount++;
+}
+
+void CGUIFontTTFBase::RemoveReference()
+{
+ // delete this object when it's reference count hits zero
+ m_referenceCount--;
+ if (!m_referenceCount)
+ g_fontManager.FreeFontFile(this);
+}
+
+
+void CGUIFontTTFBase::ClearCharacterCache()
+{
+ if (m_texture)
+ {
+ delete(m_texture);
+ }
+
+ DeleteHardwareTexture();
+
+ m_texture = NULL;
+ if (m_char)
+ delete[] m_char;
+ m_char = new Character[CHAR_CHUNK];
+ memset(m_charquick, 0, sizeof(m_charquick));
+ m_numChars = 0;
+ m_maxChars = CHAR_CHUNK;
+ // set the posX and posY so that our texture will be created on first character write.
+ m_posX = m_textureWidth;
+ m_posY = -(int)m_cellHeight;
+}
+
+void CGUIFontTTFBase::Clear()
+{
+ if (m_texture)
+ delete(m_texture);
+
+ m_texture = NULL;
+ if (m_char)
+ delete[] m_char;
+ memset(m_charquick, 0, sizeof(m_charquick));
+ m_char = NULL;
+ m_maxChars = 0;
+ m_numChars = 0;
+ m_posX = 0;
+ m_posY = 0;
+ m_nestedBeginCount = 0;
+
+ if (m_face)
+ g_freeTypeLibrary.ReleaseFont(m_face);
+ m_face = NULL;
+
+ free(m_vertex);
+ m_vertex = NULL;
+ m_vertex_count = 0;
+}
+
+bool CGUIFontTTFBase::Load(const CStdString& strFilename, float height, float aspect, float lineSpacing)
+{
+ // we now know that this object is unique - only the GUIFont objects are non-unique, so no need
+ // for reference tracking these fonts
+ m_face = g_freeTypeLibrary.GetFont(strFilename, height, aspect);
+
+ if (!m_face)
+ return false;
+
+ // grab the maximum cell height and width
+ unsigned int m_cellWidth = m_face->bbox.xMax - m_face->bbox.xMin;
+ m_cellHeight = m_face->bbox.yMax - m_face->bbox.yMin;
+ m_cellBaseLine = m_face->bbox.yMax;
+
+ unsigned int ydpi = g_freeTypeLibrary.GetDPI();
+ unsigned int xdpi = (unsigned int)MathUtils::round_int(ydpi * aspect);
+
+ m_cellWidth *= (unsigned int)(height * xdpi);
+ m_cellWidth /= (72 * m_face->units_per_EM);
+
+ m_cellHeight *= (unsigned int)(height * ydpi);
+ m_cellHeight /= (72 * m_face->units_per_EM);
+
+ m_cellBaseLine *= (unsigned int)(height * ydpi);
+ m_cellBaseLine /= (72 * m_face->units_per_EM);
+
+ // increment for good measure to give space in our texture
+ m_cellWidth++;
+ m_cellHeight+=2;
+ m_cellBaseLine++;
+
+// CLog::Log(LOGDEBUG, "%s Scaled size of font %s (%f): width = %i, height = %i, lineheight = %li",
+// __FUNCTION__, strFilename.c_str(), height, m_cellWidth, m_cellHeight, m_face->size->metrics.height / 64);
+
+ m_height = height;
+
+ if (m_texture)
+ delete(m_texture);
+
+ m_texture = NULL;
+ if (m_char)
+ delete[] m_char;
+ m_char = NULL;
+
+ m_maxChars = 0;
+ m_numChars = 0;
+
+ m_strFilename = strFilename;
+
+ m_textureHeight = 0;
+ m_textureWidth = ((m_cellHeight * CHARS_PER_TEXTURE_LINE) & ~63) + 64;
+
+ m_textureWidth = CBaseTexture::PadPow2(m_textureWidth);
+
+ if (m_textureWidth > max_texture_size) m_textureWidth = max_texture_size;
+
+ // set the posX and posY so that our texture will be created on first character write.
+ m_posX = m_textureWidth;
+ m_posY = -(int)m_cellHeight;
+
+ // cache the ellipses width
+ Character *ellipse = GetCharacter(L'.');
+ if (ellipse) m_ellipsesWidth = ellipse->advance;
+
+ return true;
+}
+
+void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors, const vecText &text, uint32_t alignment, float maxPixelWidth, bool scrolling)
+{
+ Begin();
+
+ // save the origin, which is scaled separately
+ m_originX = x;
+ m_originY = y;
+
+ // Check if we will really need to truncate or justify the text
+ if ( alignment & XBFONT_TRUNCATED )
+ {
+ if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth)
+ alignment &= ~XBFONT_TRUNCATED;
+ }
+ else if ( alignment & XBFONT_JUSTIFIED )
+ {
+ if ( maxPixelWidth <= 0.0f )
+ alignment &= ~XBFONT_JUSTIFIED;
+ }
+
+ // calculate sizing information
+ float startX = 0;
+ float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*(m_cellHeight-2) : 0; // vertical centering
+
+ if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) )
+ {
+ // Get the extent of this line
+ float w = GetTextWidthInternal( text.begin(), text.end() );
+
+ if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth )
+ w = maxPixelWidth;
+
+ if ( alignment & XBFONT_CENTER_X)
+ w *= 0.5f;
+ // Offset this line's starting position
+ startX -= w;
+ }
+
+ float spacePerLetter = 0; // for justification effects
+ if ( alignment & XBFONT_JUSTIFIED )
+ {
+ // first compute the size of the text to render in both characters and pixels
+ unsigned int lineChars = 0;
+ float linePixels = 0;
+ for (vecText::const_iterator pos = text.begin(); pos != text.end(); pos++)
+ {
+ Character *ch = GetCharacter(*pos);
+ if (ch)
+ { // spaces have multiple times the justification spacing of normal letters
+ lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1;
+ linePixels += ch->advance;
+ }
+ }
+ if (lineChars > 1)
+ spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1);
+ }
+ float cursorX = 0; // current position along the line
+
+ for (vecText::const_iterator pos = text.begin(); pos != text.end(); pos++)
+ {
+ // If starting text on a new line, determine justification effects
+ // Get the current letter in the CStdString
+ color_t color = (*pos & 0xff0000) >> 16;
+ if (color >= colors.size())
+ color = 0;
+ color = colors[color];
+
+ // grab the next character
+ Character *ch = GetCharacter(*pos);
+ if (!ch) continue;
+
+ if ( alignment & XBFONT_TRUNCATED )
+ {
+ // Check if we will be exceeded the max allowed width
+ if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth )
+ {
+ // Yup. Let's draw the ellipses, then bail
+ // Perhaps we should really bail to the next line in this case??
+ Character *period = GetCharacter(L'.');
+ if (!period)
+ break;
+
+ for (int i = 0; i < 3; i++)
+ {
+ RenderCharacter(startX + cursorX, startY, period, color, !scrolling);
+ cursorX += period->advance;
+ }
+ break;
+ }
+ }
+ else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
+ break; // exceeded max allowed width - stop rendering
+
+ RenderCharacter(startX + cursorX, startY, ch, color, !scrolling);
+ if ( alignment & XBFONT_JUSTIFIED )
+ {
+ if ((*pos & 0xffff) == L' ')
+ cursorX += ch->advance + spacePerLetter * justification_word_weight;
+ else
+ cursorX += ch->advance + spacePerLetter;
+ }
+ else
+ cursorX += ch->advance;
+ }
+
+ End();
+}
+
+// this routine assumes a single line (i.e. it was called from GUITextLayout)
+float CGUIFontTTFBase::GetTextWidthInternal(vecText::const_iterator start, vecText::const_iterator end)
+{
+ float width = 0;
+ while (start != end)
+ {
+ Character *c = GetCharacter(*start++);
+ if (c) width += c->advance;
+ }
+ return width;
+}
+
+float CGUIFontTTFBase::GetCharWidthInternal(character_t ch)
+{
+ Character *c = GetCharacter(ch);
+ if (c) return c->advance;
+ return 0;
+}
+
+float CGUIFontTTFBase::GetTextHeight(float lineSpacing, int numLines) const
+{
+ return (float)(numLines - 1) * GetLineHeight(lineSpacing) + (m_cellHeight - 2); // -2 as we increment this for space in our texture
+}
+
+float CGUIFontTTFBase::GetLineHeight(float lineSpacing) const
+{
+ if (m_face)
+ return lineSpacing * m_face->size->metrics.height / 64.0f;
+ return 0.0f;
+}
+
+CGUIFontTTFBase::Character* CGUIFontTTFBase::GetCharacter(character_t chr)
+{
+ wchar_t letter = (wchar_t)(chr & 0xffff);
+ character_t style = (chr & 0x3000000) >> 24;
+
+ // ignore linebreaks
+ if (letter == L'\r')
+ return NULL;
+
+ // quick access to ascii chars
+ if (letter < 255)
+ {
+ character_t ch = (style << 8) | letter;
+ if (m_charquick[ch])
+ return m_charquick[ch];
+ }
+
+ // letters are stored based on style and letter
+ character_t ch = (style << 16) | letter;
+
+ int low = 0;
+ int high = m_numChars - 1;
+ int mid;
+ while (low <= high)
+ {
+ mid = (low + high) >> 1;
+ if (ch > m_char[mid].letterAndStyle)
+ low = mid + 1;
+ else if (ch < m_char[mid].letterAndStyle)
+ high = mid - 1;
+ else
+ return &m_char[mid];
+ }
+ // if we get to here, then low is where we should insert the new character
+
+ // increase the size of the buffer if we need it
+ if (m_numChars >= m_maxChars)
+ { // need to increase the size of the buffer
+ Character *newTable = new Character[m_maxChars + CHAR_CHUNK];
+ if (m_char)
+ {
+ memcpy(newTable, m_char, low * sizeof(Character));
+ memcpy(newTable + low + 1, m_char + low, (m_numChars - low) * sizeof(Character));
+ delete[] m_char;
+ }
+ m_char = newTable;
+ m_maxChars += CHAR_CHUNK;
+
+ }
+ else
+ { // just move the data along as necessary
+ memmove(m_char + low + 1, m_char + low, (m_numChars - low) * sizeof(Character));
+ }
+ // render the character to our texture
+ // must End() as we can't render text to our texture during a Begin(), End() block
+ unsigned int nestedBeginCount = m_nestedBeginCount;
+ m_nestedBeginCount = 1;
+ if (nestedBeginCount) End();
+ if (!CacheCharacter(letter, style, m_char + low))
+ { // unable to cache character - try clearing them all out and starting over
+ CLog::Log(LOGDEBUG, "GUIFontTTF::GetCharacter: Unable to cache character. Clearing character cache of %i characters", m_numChars);
+ ClearCharacterCache();
+ low = 0;
+ if (!CacheCharacter(letter, style, m_char + low))
+ {
+ CLog::Log(LOGERROR, "GUIFontTTF::GetCharacter: Unable to cache character (out of memory?)");
+ if (nestedBeginCount) Begin();
+ m_nestedBeginCount = nestedBeginCount;
+ return NULL;
+ }
+ }
+ if (nestedBeginCount) Begin();
+ m_nestedBeginCount = nestedBeginCount;
+
+ // fixup quick access
+ memset(m_charquick, 0, sizeof(m_charquick));
+ for(int i=0;i<m_numChars;i++)
+ {
+ if ((m_char[i].letterAndStyle & 0xffff) < 255)
+ {
+ character_t ch = ((m_char[i].letterAndStyle & 0xffff0000) >> 8) | (m_char[i].letterAndStyle & 0xff);
+ m_charquick[ch] = m_char+i;
+ }
+ }
+
+ return m_char + low;
+}
+
+bool CGUIFontTTFBase::CacheCharacter(wchar_t letter, uint32_t style, Character *ch)
+{
+ int glyph_index = FT_Get_Char_Index( m_face, letter );
+
+ FT_Glyph glyph = NULL;
+ if (FT_Load_Glyph( m_face, glyph_index, FT_LOAD_TARGET_LIGHT ))
+ {
+ CLog::Log(LOGDEBUG, "%s Failed to load glyph %x", __FUNCTION__, letter);
+ return false;
+ }
+ // make bold if applicable
+ if (style & FONT_STYLE_BOLD)
+ EmboldenGlyph(m_face->glyph);
+ // and italics if applicable
+ if (style & FONT_STYLE_ITALICS)
+ ObliqueGlyph(m_face->glyph);
+ // grab the glyph
+ if (FT_Get_Glyph(m_face->glyph, &glyph))
+ {
+ CLog::Log(LOGDEBUG, "%s Failed to get glyph %x", __FUNCTION__, letter);
+ return false;
+ }
+ // render the glyph
+ if (FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, NULL, 1))
+ {
+ CLog::Log(LOGDEBUG, "%s Failed to render glyph %x to a bitmap", __FUNCTION__, letter);
+ return false;
+ }
+ FT_BitmapGlyph bitGlyph = (FT_BitmapGlyph)glyph;
+ FT_Bitmap bitmap = bitGlyph->bitmap;
+ if (bitGlyph->left < 0)
+ m_posX += -bitGlyph->left;
+
+ // check we have enough room for the character
+ if (m_posX + bitGlyph->left + bitmap.width > (int)m_textureWidth)
+ { // no space - gotta drop to the next line (which means creating a new texture and copying it across)
+ m_posX = 0;
+ m_posY += m_cellHeight;
+ if (bitGlyph->left < 0)
+ m_posX += -bitGlyph->left;
+
+ if(m_posY + m_cellHeight >= m_textureHeight)
+ {
+ // create the new larger texture
+ unsigned int newHeight = m_posY + m_cellHeight;
+ // check for max height (can't be more than max_texture_size texels
+ if (newHeight > max_texture_size)
+ {
+ CLog::Log(LOGDEBUG, "GUIFontTTF::CacheCharacter: New cache texture is too large (%u > %u pixels long)", newHeight, max_texture_size);
+ FT_Done_Glyph(glyph);
+ return false;
+ }
+
+ CBaseTexture* newTexture = NULL;
+ newTexture = ReallocTexture(newHeight);
+ if(newTexture == NULL)
+ {
+ FT_Done_Glyph(glyph);
+ return false;
+ }
+ m_texture = newTexture;
+ }
+ }
+
+ // set the character in our table
+ ch->letterAndStyle = (style << 16) | letter;
+ ch->offsetX = (short)bitGlyph->left;
+ ch->offsetY = (short)max((short)m_cellBaseLine - bitGlyph->top, 0);
+ ch->left = (float)m_posX + ch->offsetX;
+ ch->top = (float)m_posY + ch->offsetY;
+ ch->right = ch->left + bitmap.width;
+ ch->bottom = ch->top + bitmap.rows;
+ ch->advance = (float)MathUtils::round_int( (float)m_face->glyph->advance.x / 64 );
+
+ // we need only render if we actually have some pixels
+ if (bitmap.width * bitmap.rows)
+ {
+ CopyCharToTexture(bitGlyph, ch);
+ }
+ m_posX += (unsigned short)max(ch->right - ch->left + ch->offsetX, ch->advance + 1);
+ m_numChars++;
+
+ m_textureScaleX = 1.0f / m_textureWidth;
+ m_textureScaleY = 1.0f / m_textureHeight;
+
+ // free the glyph
+ FT_Done_Glyph(glyph);
+
+ return true;
+}
+
+void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX)
+{
+ // actual image width isn't same as the character width as that is
+ // just baseline width and height should include the descent
+ const float width = ch->right - ch->left;
+ const float height = ch->bottom - ch->top;
+
+ // posX and posY are relative to our origin, and the textcell is offset
+ // from our (posX, posY). Plus, these are unscaled quantities compared to the underlying GUI resolution
+ CRect vertex((posX + ch->offsetX) * g_graphicsContext.GetGUIScaleX(),
+ (posY + ch->offsetY) * g_graphicsContext.GetGUIScaleY(),
+ (posX + ch->offsetX + width) * g_graphicsContext.GetGUIScaleX(),
+ (posY + ch->offsetY + height) * g_graphicsContext.GetGUIScaleY());
+ vertex += CPoint(m_originX, m_originY);
+ CRect texture(ch->left, ch->top, ch->right, ch->bottom);
+ g_graphicsContext.ClipRect(vertex, texture);
+
+ // transform our positions - note, no scaling due to GUI calibration/resolution occurs
+ float x[4];
+
+ x[0] = g_graphicsContext.ScaleFinalXCoord(vertex.x1, vertex.y1);
+ x[1] = g_graphicsContext.ScaleFinalXCoord(vertex.x2, vertex.y1);
+ x[2] = g_graphicsContext.ScaleFinalXCoord(vertex.x2, vertex.y2);
+ x[3] = g_graphicsContext.ScaleFinalXCoord(vertex.x1, vertex.y2);
+
+ if (roundX)
+ {
+ // We only round the "left" side of the character, and then use the direction of rounding to
+ // move the "right" side of the character. This ensures that a constant width is kept when rendering
+ // the same letter at the same size at different places of the screen, avoiding the problem
+ // of the "left" side rounding one way while the "right" side rounds the other way, thus getting
+ // altering the width of thin characters substantially. This only really works for positive
+ // coordinates (due to the direction of truncation for negatives) but this is the only case that
+ // really interests us anyway.
+ float rx0 = (float)MathUtils::round_int(x[0]);
+ float rx3 = (float)MathUtils::round_int(x[3]);
+ x[1] = (float)MathUtils::truncate_int(x[1]);
+ x[2] = (float)MathUtils::truncate_int(x[2]);
+ if (rx0 > x[0])
+ x[1] += 1;
+ if (rx3 > x[3])
+ x[2] += 1;
+ x[0] = rx0;
+ x[3] = rx3;
+ }
+
+ float y1 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalYCoord(vertex.x1, vertex.y1));
+ float y2 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalYCoord(vertex.x2, vertex.y1));
+ float y3 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalYCoord(vertex.x2, vertex.y2));
+ float y4 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalYCoord(vertex.x1, vertex.y2));
+
+ float z1 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalZCoord(vertex.x1, vertex.y1));
+ float z2 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalZCoord(vertex.x2, vertex.y1));
+ float z3 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalZCoord(vertex.x2, vertex.y2));
+ float z4 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalZCoord(vertex.x1, vertex.y2));
+
+ // tex coords converted to 0..1 range
+ float tl = texture.x1 * m_textureScaleX;
+ float tr = texture.x2 * m_textureScaleX;
+ float tt = texture.y1 * m_textureScaleY;
+ float tb = texture.y2 * m_textureScaleY;
+
+ // grow the vertex buffer if required
+ if(m_vertex_count >= m_vertex_size)
+ {
+ m_vertex_size *= 2;
+ m_vertex = (SVertex*)realloc(m_vertex, m_vertex_size * sizeof(SVertex));
+ }
+
+ m_color = color;
+ SVertex* v = m_vertex + m_vertex_count;
+
+ for(int i = 0; i < 4; i++)
+ {
+ v[i].r = GET_R(color);
+ v[i].g = GET_G(color);
+ v[i].b = GET_B(color);
+ v[i].a = GET_A(color);
+ }
+
+ v[0].u = tl;
+ v[0].v = tt;
+ v[0].x = x[0];
+ v[0].y = y1;
+ v[0].z = z1;
+
+ v[1].u = tr;
+ v[1].v = tt;
+ v[1].x = x[1];
+ v[1].y = y2;
+ v[1].z = z2;
+
+ v[2].u = tr;
+ v[2].v = tb;
+ v[2].x = x[2];
+ v[2].y = y3;
+ v[2].z = z3;
+
+ v[3].u = tl;
+ v[3].v = tb;
+ v[3].x = x[3];
+ v[3].y = y4;
+ v[3].z = z4;
+
+ RenderInternal(v);
+
+ m_vertex_count+=4;
+}
+
+// Oblique code - original taken from freetype2 (ftsynth.c)
+void CGUIFontTTFBase::ObliqueGlyph(FT_GlyphSlot slot)
+{
+ /* only oblique outline glyphs */
+ if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
+ return;
+
+ /* we don't touch the advance width */
+
+ /* For italic, simply apply a shear transform, with an angle */
+ /* of about 12 degrees. */
+
+ FT_Matrix transform;
+ transform.xx = 0x10000L;
+ transform.yx = 0x00000L;
+
+ transform.xy = 0x06000L;
+ transform.yy = 0x10000L;
+
+ FT_Outline_Transform( &slot->outline, &transform );
+}
+
+
+// Embolden code - original taken from freetype2 (ftsynth.c)
+void CGUIFontTTFBase::EmboldenGlyph(FT_GlyphSlot slot)
+{
+ if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
+ return;
+
+ /* some reasonable strength */
+ FT_Pos strength = FT_MulFix( m_face->units_per_EM,
+ m_face->size->metrics.y_scale ) / 24;
+
+ FT_BBox bbox_before, bbox_after;
+ FT_Outline_Get_CBox( &slot->outline, &bbox_before );
+ FT_Outline_Embolden( &slot->outline, strength ); // ignore error
+ FT_Outline_Get_CBox( &slot->outline, &bbox_after );
+
+ FT_Pos dx = bbox_after.xMax - bbox_before.xMax;
+ FT_Pos dy = bbox_after.yMax - bbox_before.yMax;
+
+ if ( slot->advance.x )
+ slot->advance.x += dx;
+
+ if ( slot->advance.y )
+ slot->advance.y += dy;
+
+ slot->metrics.width += dx;
+ slot->metrics.height += dy;
+ slot->metrics.horiBearingY += dy;
+ slot->metrics.horiAdvance += dx;
+ slot->metrics.vertBearingX -= dx / 2;
+ slot->metrics.vertBearingY += dy;
+ slot->metrics.vertAdvance += dy;
+}
+
+
diff --git a/guilib/GUIFontTTF.h b/guilib/GUIFontTTF.h
new file mode 100644
index 0000000000..098fbe0c0a
--- /dev/null
+++ b/guilib/GUIFontTTF.h
@@ -0,0 +1,182 @@
+/*!
+\file GUIFont.h
+\brief
+*/
+
+#ifndef CGUILIB_GUIFONTTTF_H
+#define CGUILIB_GUIFONTTTF_H
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+// forward definition
+class CBaseTexture;
+
+struct FT_FaceRec_;
+struct FT_LibraryRec_;
+struct FT_GlyphSlotRec_;
+struct FT_BitmapGlyphRec_;
+
+typedef struct FT_FaceRec_ *FT_Face;
+typedef struct FT_LibraryRec_ *FT_Library;
+typedef struct FT_GlyphSlotRec_ *FT_GlyphSlot;
+typedef struct FT_BitmapGlyphRec_ *FT_BitmapGlyph;
+
+typedef uint32_t character_t;
+typedef uint32_t color_t;
+typedef std::vector<character_t> vecText;
+typedef std::vector<color_t> vecColors;
+
+/*!
+ \ingroup textures
+ \brief
+ */
+
+typedef struct _SVertex
+{
+ float u, v;
+ unsigned char r, g, b, a;
+ float x, y, z;
+} SVertex;
+
+
+class CGUIFontTTFBase
+{
+ friend class CGUIFont;
+
+public:
+
+ CGUIFontTTFBase(const CStdString& strFileName);
+ virtual ~CGUIFontTTFBase(void);
+
+ void Clear();
+
+ bool Load(const CStdString& strFilename, float height = 20.0f, float aspect = 1.0f, float lineSpacing = 1.0f);
+
+ virtual void Begin() = 0;
+ virtual void End() = 0;
+
+ const CStdString& GetFileName() const { return m_strFileName; };
+
+protected:
+ struct Character
+ {
+ short offsetX, offsetY;
+ float left, top, right, bottom;
+ float advance;
+ character_t letterAndStyle;
+ };
+ void AddReference();
+ void RemoveReference();
+
+ float GetTextWidthInternal(vecText::const_iterator start, vecText::const_iterator end);
+ float GetCharWidthInternal(character_t ch);
+ float GetTextHeight(float lineSpacing, int numLines) const;
+ float GetLineHeight(float lineSpacing) const;
+
+ void DrawTextInternal(float x, float y, const vecColors &colors, const vecText &text,
+ uint32_t alignment, float maxPixelWidth, bool scrolling);
+
+ void DrawTextInternal(float x, float y, color_t color, const vecText &text,
+ uint32_t alignment, float maxPixelWidth, bool scrolling)
+ {
+ vecColors colors;
+ colors.push_back(color);
+ DrawTextInternal(x, y, colors, text, alignment, maxPixelWidth, scrolling);
+ }
+
+ float m_height;
+ CStdString m_strFilename;
+
+ // Stuff for pre-rendering for speed
+ inline Character *GetCharacter(character_t letter);
+ bool CacheCharacter(wchar_t letter, uint32_t style, Character *ch);
+ void RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX);
+ void ClearCharacterCache();
+
+ virtual CBaseTexture* ReallocTexture(unsigned int& newHeight) = 0;
+ virtual bool CopyCharToTexture(FT_BitmapGlyph bitGlyph, Character *ch) = 0;
+ virtual void DeleteHardwareTexture() = 0;
+ virtual void RenderInternal(SVertex* v) = 0;
+
+ // modifying glyphs
+ void EmboldenGlyph(FT_GlyphSlot slot);
+ void ObliqueGlyph(FT_GlyphSlot slot);
+
+ CBaseTexture* m_texture; // texture that holds our rendered characters (8bit alpha only)
+
+ unsigned int m_textureWidth; // width of our texture
+ unsigned int m_textureHeight; // heigth of our texture
+ int m_posX; // current position in the texture
+ int m_posY;
+
+ color_t m_color;
+
+ Character *m_char; // our characters
+ Character *m_charquick[256*4]; // ascii chars (4 styles) here
+ int m_maxChars; // size of character array (can be incremented)
+ int m_numChars; // the current number of cached characters
+
+ float m_ellipsesWidth; // this is used every character (width of '.')
+
+ unsigned int m_cellBaseLine;
+ unsigned int m_cellHeight;
+
+ unsigned int m_nestedBeginCount; // speedups
+
+ // freetype stuff
+ FT_Face m_face;
+
+ float m_originX;
+ float m_originY;
+
+ bool m_bTextureLoaded;
+ unsigned int m_nTexture;
+
+ SVertex* m_vertex;
+ int m_vertex_count;
+ int m_vertex_size;
+
+ float m_textureScaleX;
+ float m_textureScaleY;
+
+ static int justification_word_weight;
+ static unsigned int max_texture_size;
+
+ CStdString m_strFileName;
+
+private:
+ int m_referenceCount;
+};
+
+#if defined(HAS_GL)
+#include "GUIFontTTFGL.h"
+#define CGUIFontTTF CGUIFontTTFGL
+#elif defined(HAS_GLES)
+#include "GUIFontTTFGLES.h"
+#define CGUIFontTTF CGUIFontTTFGLES
+#elif defined(HAS_DX)
+#include "GUIFontTTFDX.h"
+#define CGUIFontTTF CGUIFontTTFDX
+#endif
+
+#endif
diff --git a/guilib/GUIFontTTFDX.cpp b/guilib/GUIFontTTFDX.cpp
new file mode 100644
index 0000000000..85e11ab867
--- /dev/null
+++ b/guilib/GUIFontTTFDX.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIFont.h"
+#include "GUIFontTTFDX.h"
+#include "GUIFontManager.h"
+#include "Texture.h"
+#include "gui3d.h"
+#include "WindowingFactory.h"
+
+// stuff for freetype
+#include "ft2build.h"
+
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+
+using namespace std;
+
+#ifdef HAS_DX
+
+struct CUSTOMVERTEX
+{
+ FLOAT x, y, z;
+ DWORD color;
+ FLOAT tu, tv; // Texture coordinates
+};
+
+
+CGUIFontTTFDX::CGUIFontTTFDX(const CStdString& strFileName)
+: CGUIFontTTFBase(strFileName)
+{
+
+}
+
+CGUIFontTTFDX::~CGUIFontTTFDX(void)
+{
+
+}
+
+void CGUIFontTTFDX::RenderInternal(SVertex* v)
+{
+ CUSTOMVERTEX verts[4] = {
+ { v[0].x-0.5f, v[0].y-0.5f, v[0].z, m_color, v[0].u, v[0].v},
+ { v[1].x-0.5f, v[1].y-0.5f, v[1].z, m_color, v[1].u, v[1].v},
+ { v[2].x-0.5f, v[2].y-0.5f, v[2].z, m_color, v[2].u, v[2].v},
+ { v[3].x-0.5f, v[3].y-0.5f, v[3].z, m_color, v[3].u, v[3].v}
+ };
+
+ g_Windowing.Get3DDevice()->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(CUSTOMVERTEX));
+}
+
+void CGUIFontTTFDX::Begin()
+{
+ LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
+
+ if (m_nestedBeginCount == 0)
+ {
+ // just have to blit from our texture.
+ pD3DDevice->SetTexture( 0, m_texture->GetTextureObject() );
+
+ pD3DDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
+ pD3DDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
+ pD3DDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
+ pD3DDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
+ pD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); // only use diffuse
+ pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
+ pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
+ pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
+ pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
+
+ // no other texture stages needed
+ pD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE);
+
+ pD3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
+ pD3DDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );
+ pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
+ pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
+ pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
+ pD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
+ pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
+ pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE);
+
+ pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
+ }
+ // Keep track of the nested begin/end calls.
+ m_vertex_count = 0;
+ m_nestedBeginCount++;
+}
+
+void CGUIFontTTFDX::End()
+{
+ LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
+
+ if (m_nestedBeginCount == 0)
+ return;
+
+ if (--m_nestedBeginCount > 0)
+ return;
+
+ pD3DDevice->SetTexture(0, NULL);
+ pD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
+}
+
+CBaseTexture* CGUIFontTTFDX::ReallocTexture(unsigned int& newHeight)
+{
+ CBaseTexture* pNewTexture = new CTexture(m_textureWidth, newHeight, 8);
+
+ if(pNewTexture == NULL)
+ return NULL;
+
+ pNewTexture->CreateTextureObject();
+
+ LPDIRECT3DTEXTURE9 newTexture = pNewTexture->GetTextureObject();
+
+ if(newTexture == NULL)
+ return NULL;
+
+ // correct texture sizes
+ D3DSURFACE_DESC desc;
+ newTexture->GetLevelDesc(0, &desc);
+ m_textureHeight = desc.Height;
+ m_textureWidth = desc.Width;
+
+ D3DLOCKED_RECT rect;
+ newTexture->LockRect(0, &rect, NULL, 0);
+ memset(rect.pBits, 0, rect.Pitch * m_textureHeight);
+ newTexture->UnlockRect(0);
+
+ if (m_texture)
+ { // copy across from our current one using gpu
+ LPDIRECT3DSURFACE9 pTarget, pSource;
+ newTexture->GetSurfaceLevel(0, &pTarget);
+ m_texture->GetTextureObject()->GetSurfaceLevel(0, &pSource);
+
+ // TODO:DIRECTX - this is probably really slow, but UpdateSurface() doesn't like rendering from non-system textures
+ D3DXLoadSurfaceFromSurface(pTarget, NULL, NULL, pSource, NULL, NULL, D3DX_FILTER_NONE, 0);
+
+ SAFE_RELEASE(pTarget);
+ SAFE_RELEASE(pSource);
+ delete m_texture;
+ }
+
+ return pNewTexture;
+}
+
+bool CGUIFontTTFDX::CopyCharToTexture(FT_BitmapGlyph bitGlyph, Character* ch)
+{
+ FT_Bitmap bitmap = bitGlyph->bitmap;
+
+ // render this onto our normal texture using gpu
+ LPDIRECT3DSURFACE9 target;
+ m_texture->GetTextureObject()->GetSurfaceLevel(0, &target);
+
+ RECT sourcerect = { 0, 0, bitmap.width, bitmap.rows };
+ RECT targetrect;
+ targetrect.top = m_posY + ch->offsetY;
+ targetrect.left = m_posX + bitGlyph->left;
+ targetrect.bottom = targetrect.top + bitmap.rows;
+ targetrect.right = targetrect.left + bitmap.width;
+
+ D3DXLoadSurfaceFromMemory( target, NULL, &targetrect,
+ bitmap.buffer, D3DFMT_LIN_A8, bitmap.pitch, NULL, &sourcerect,
+ D3DX_FILTER_NONE, 0x00000000);
+
+ SAFE_RELEASE(target);
+
+ return TRUE;
+}
+
+
+void CGUIFontTTFDX::DeleteHardwareTexture()
+{
+
+}
+
+
+#endif
diff --git a/guilib/GUIFontTTFDX.h b/guilib/GUIFontTTFDX.h
new file mode 100644
index 0000000000..96b433d77a
--- /dev/null
+++ b/guilib/GUIFontTTFDX.h
@@ -0,0 +1,55 @@
+/*
+* Copyright (C) 2005-2008 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+/*!
+\file GUIFont.h
+\brief
+*/
+
+#ifndef CGUILIB_GUIFONTTTF_DX_H
+#define CGUILIB_GUIFONTTTF_DX_H
+#pragma once
+
+
+#include "GUIFontTTF.h"
+
+
+/*!
+ \ingroup textures
+ \brief
+ */
+class CGUIFontTTFDX : public CGUIFontTTFBase
+{
+public:
+ CGUIFontTTFDX(const CStdString& strFileName);
+ virtual ~CGUIFontTTFDX(void);
+
+ virtual void Begin();
+ virtual void End();
+
+protected:
+ virtual CBaseTexture* ReallocTexture(unsigned int& newHeight);
+ virtual bool CopyCharToTexture(FT_BitmapGlyph bitGlyph, Character *ch);
+ virtual void DeleteHardwareTexture();
+ virtual void RenderInternal(SVertex* v);
+};
+
+#endif
diff --git a/guilib/GUIFontTTFGL.cpp b/guilib/GUIFontTTFGL.cpp
new file mode 100644
index 0000000000..7472bafba1
--- /dev/null
+++ b/guilib/GUIFontTTFGL.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "GUIFont.h"
+#include "GUIFontTTFGL.h"
+#include "GUIFontManager.h"
+#include "Texture.h"
+#include "GraphicContext.h"
+#include "gui3d.h"
+#include "utils/log.h"
+
+// stuff for freetype
+#ifndef _LINUX
+#include "ft2build.h"
+#else
+#include <ft2build.h>
+#endif
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+
+using namespace std;
+
+#ifdef HAS_GL
+
+
+CGUIFontTTFGL::CGUIFontTTFGL(const CStdString& strFileName)
+: CGUIFontTTFBase(strFileName)
+{
+
+}
+
+CGUIFontTTFGL::~CGUIFontTTFGL(void)
+{
+
+}
+
+void CGUIFontTTFGL::Begin()
+{
+ if (m_nestedBeginCount == 0)
+ {
+ if (!m_bTextureLoaded)
+ {
+ // Have OpenGL generate a texture object handle for us
+ glGenTextures(1, (GLuint*) &m_nTexture);
+
+ // Bind the texture object
+ glBindTexture(GL_TEXTURE_2D, m_nTexture);
+ glEnable(GL_TEXTURE_2D);
+
+ // Set the texture's stretching properties
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ // Set the texture image -- THIS WORKS, so the pixels must be wrong.
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_texture->GetWidth(), m_texture->GetHeight(), 0,
+ GL_ALPHA, GL_UNSIGNED_BYTE, m_texture->GetPixels());
+
+ VerifyGLState();
+ m_bTextureLoaded = true;
+ }
+
+ // Turn Blending On
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, m_nTexture);
+ glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ VerifyGLState();
+
+ m_vertex_count = 0;
+ }
+ // Keep track of the nested begin/end calls.
+ m_nestedBeginCount++;
+}
+
+void CGUIFontTTFGL::End()
+{
+ if (m_nestedBeginCount == 0)
+ return;
+
+ if (--m_nestedBeginCount > 0)
+ return;
+
+ glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
+
+ glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, r));
+ glVertexPointer (3, GL_FLOAT , sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, x));
+ glTexCoordPointer(2, GL_FLOAT , sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, u));
+ glEnableClientState(GL_COLOR_ARRAY);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDrawArrays(GL_QUADS, 0, m_vertex_count);
+ glPopClientAttrib();
+}
+
+CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight)
+{
+ newHeight = CBaseTexture::PadPow2(newHeight);
+
+ CBaseTexture* newTexture = new CTexture(m_textureWidth, newHeight, 8);
+/* yuvalt
+
+#ifdef __APPLE__
+ // Because of an SDL bug (?), bpp gets set to 4 even though we asked for 1, in fullscreen mode.
+ // To be completely honest, we probably shouldn't even be using an SDL surface in OpenGL mode, since
+ // we only use it to store the image before copying it (no blitting!) to an OpenGL texture.
+ //
+ if (newTexture->GetPitch() != m_textureWidth)
+ newTexture->SetPitch(m_textureWidth);
+#endif
+
+*/
+
+ if (!newTexture || newTexture->GetPixels() == NULL)
+ {
+ CLog::Log(LOGERROR, "GUIFontTTFGL::CacheCharacter: Error creating new cache texture for size %f", m_height);
+ return NULL;
+ }
+ m_textureHeight = newTexture->GetHeight();
+ m_textureWidth = newTexture->GetWidth();
+
+ if (m_texture)
+ {
+ unsigned char* src = (unsigned char*) m_texture->GetPixels();
+ unsigned char* dst = (unsigned char*) newTexture->GetPixels();
+ for (unsigned int y = 0; y < m_texture->GetHeight(); y++)
+ {
+ memcpy(dst, src, m_texture->GetPitch());
+ src += m_texture->GetPitch();
+ dst += newTexture->GetPitch();
+ }
+ delete m_texture;
+ }
+
+ return newTexture;
+}
+
+bool CGUIFontTTFGL::CopyCharToTexture(FT_BitmapGlyph bitGlyph, Character* ch)
+{
+ //SDL_LockSurface(m_texture);
+
+ FT_Bitmap bitmap = bitGlyph->bitmap;
+
+ unsigned char* source = (unsigned char*) bitmap.buffer;
+ unsigned char* target = (unsigned char*) m_texture->GetPixels() + (m_posY + ch->offsetY) * m_texture->GetPitch() + m_posX + bitGlyph->left;
+
+ for (int y = 0; y < bitmap.rows; y++)
+ {
+ memcpy(target, source, bitmap.width);
+ source += bitmap.width;
+ target += m_texture->GetPitch();
+ }
+ // THE SOURCE VALUES ARE THE SAME IN BOTH SITUATIONS.
+
+ // Since we have a new texture, we need to delete the old one
+ // the Begin(); End(); stuff is handled by whoever called us
+ if (m_bTextureLoaded)
+ {
+ g_graphicsContext.BeginPaint(); //FIXME
+ DeleteHardwareTexture();
+ g_graphicsContext.EndPaint();
+ m_bTextureLoaded = false;
+ }
+
+ //SDL_UnlockSurface(m_texture);
+
+ return TRUE;
+}
+
+
+void CGUIFontTTFGL::DeleteHardwareTexture()
+{
+ if (m_bTextureLoaded)
+ {
+ if (glIsTexture(m_nTexture))
+ glDeleteTextures(1, (GLuint*) &m_nTexture);
+ m_bTextureLoaded = false;
+ }
+}
+
+#endif
diff --git a/guilib/GUIFontTTFGL.h b/guilib/GUIFontTTFGL.h
new file mode 100644
index 0000000000..b23a9d3af3
--- /dev/null
+++ b/guilib/GUIFontTTFGL.h
@@ -0,0 +1,56 @@
+/*
+* Copyright (C) 2005-2008 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+/*!
+\file GUIFont.h
+\brief
+*/
+
+#ifndef CGUILIB_GUIFONTTTF_GL_H
+#define CGUILIB_GUIFONTTTF_GL_H
+#pragma once
+
+
+#include "GUIFontTTF.h"
+
+
+/*!
+ \ingroup textures
+ \brief
+ */
+class CGUIFontTTFGL : public CGUIFontTTFBase
+{
+public:
+ CGUIFontTTFGL(const CStdString& strFileName);
+ virtual ~CGUIFontTTFGL(void);
+
+ virtual void Begin();
+ virtual void End();
+
+protected:
+ virtual CBaseTexture* ReallocTexture(unsigned int& newHeight);
+ virtual bool CopyCharToTexture(FT_BitmapGlyph bitGlyph, Character *ch);
+ virtual void DeleteHardwareTexture();
+ virtual void RenderInternal(SVertex* v) {}
+
+};
+
+#endif
diff --git a/guilib/GUIFontTTFGLES.cpp b/guilib/GUIFontTTFGLES.cpp
new file mode 100644
index 0000000000..8adcefebc2
--- /dev/null
+++ b/guilib/GUIFontTTFGLES.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "GUIFont.h"
+#include "GUIFontTTFGL.h"
+#include "GUIFontManager.h"
+#include "Texture.h"
+#include "GraphicContext.h"
+#include "gui3d.h"
+
+// stuff for freetype
+#ifndef _LINUX
+#include "ft2build.h"
+#else
+#include <ft2build.h>
+#endif
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+
+using namespace std;
+
+#ifdef HAS_GLES
+
+CGUIFontTTFGLES::CGUIFontTTFGLES(const CStdString& strFileName)
+: CGUIFontTTFBase(strFileName)
+{
+
+}
+
+CGUIFontTTFGLES::~CGUIFontTTFGLES(void)
+{
+
+}
+
+void CGUIFontTTFGLES::Begin()
+{
+ // TODO: GLES
+}
+
+void CGUIFontTTFGLES::End()
+{
+ // TODO: GLES
+}
+
+CBaseTexture* CGUIFontTTFGLES::ReallocTexture(unsigned int& newHeight)
+{
+ // TODO: GLES
+ return NULL;
+}
+
+bool CGUIFontTTFGLES::CopyCharToTexture(FT_BitmapGlyph bitGlyph, Character* ch)
+{
+ // TODO: GLES
+ return false;
+}
+
+void CGUIFontTTFGLES::DeleteHardwareTexture()
+{
+ // TODO: GLES
+}
+
+#endif
diff --git a/guilib/GUIFontTTFGLES.h b/guilib/GUIFontTTFGLES.h
new file mode 100644
index 0000000000..207da8c57f
--- /dev/null
+++ b/guilib/GUIFontTTFGLES.h
@@ -0,0 +1,56 @@
+/*
+* Copyright (C) 2005-2008 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+/*!
+\file GUIFont.h
+\brief
+*/
+
+#ifndef CGUILIB_GUIFONTTTF_GLES_H
+#define CGUILIB_GUIFONTTTF_GLES_H
+#pragma once
+
+
+#include "GUIFontTTF.h"
+
+
+/*!
+ \ingroup textures
+ \brief
+ */
+class CGUIFontTTFGLES : public CGUIFontTTFBase
+{
+public:
+ CGUIFontTTFGLES(const CStdString& strFileName);
+ virtual ~CGUIFontTTFGLES(void);
+
+ virtual void Begin();
+ virtual void End();
+
+protected:
+ virtual CBaseTexture* ReallocTexture(unsigned int& newHeight);
+ virtual bool CopyCharToTexture(FT_BitmapGlyph bitGlyph, Character *ch);
+ virtual void DeleteHardwareTexture();
+ virtual void RenderInternal(SVertex* v) {}
+
+};
+
+#endif
diff --git a/guilib/GUIImage.cpp b/guilib/GUIImage.cpp
new file mode 100644
index 0000000000..b2f444eea4
--- /dev/null
+++ b/guilib/GUIImage.cpp
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIImage.h"
+#include "TextureManager.h"
+#include "utils/log.h"
+
+using namespace std;
+
+CGUIImage::CGUIImage(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& texture)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+ , m_texture(posX, posY, width, height, texture)
+{
+ m_crossFadeTime = 0;
+ m_currentFadeTime = 0;
+ m_lastRenderTime = 0;
+ ControlType = GUICONTROL_IMAGE;
+ m_bDynamicResourceAlloc=false;
+}
+
+CGUIImage::CGUIImage(const CGUIImage &left)
+ : CGUIControl(left), m_texture(left.m_texture)
+{
+ m_info = left.m_info;
+ m_crossFadeTime = left.m_crossFadeTime;
+ // defaults
+ m_currentFadeTime = 0;
+ m_lastRenderTime = 0;
+ ControlType = GUICONTROL_IMAGE;
+ m_bDynamicResourceAlloc=false;
+}
+
+CGUIImage::~CGUIImage(void)
+{
+
+}
+
+void CGUIImage::UpdateVisibility(const CGUIListItem *item)
+{
+ CGUIControl::UpdateVisibility(item);
+
+ // now that we've checked for conditional info, we can
+ // check for allocation
+ AllocateOnDemand();
+}
+
+void CGUIImage::UpdateInfo(const CGUIListItem *item)
+{
+ if (m_info.IsConstant())
+ return; // nothing to do
+
+ // don't allow image to change while animating out
+ if (HasRendered() && IsAnimating(ANIM_TYPE_HIDDEN) && !IsVisibleFromSkin())
+ return;
+
+ if (item)
+ SetFileName(m_info.GetItemLabel(item, true));
+ else
+ SetFileName(m_info.GetLabel(m_parentID, true));
+}
+
+void CGUIImage::AllocateOnDemand()
+{
+ // if we're hidden, we can free our resources and return
+ if (!IsVisible() && m_visible != DELAYED)
+ {
+ if (m_bDynamicResourceAlloc && m_texture.IsAllocated())
+ FreeResourcesButNotAnims();
+ return;
+ }
+
+ // either visible or delayed - we need the resources allocated in either case
+ if (!m_texture.IsAllocated())
+ AllocResources();
+}
+
+void CGUIImage::Render()
+{
+ if (!IsVisible()) return;
+
+ // check whether our image failed to allocate, and if so drop back to the fallback image
+ if (m_texture.FailedToAlloc() && !m_texture.GetFileName().Equals(m_info.GetFallback()))
+ m_texture.SetFileName(m_info.GetFallback());
+
+ if (m_crossFadeTime)
+ {
+ // make sure our texture has started allocating
+ m_texture.AllocResources();
+
+ // compute the frame time
+ unsigned int frameTime = 0;
+ unsigned int currentTime = timeGetTime();
+ if (m_lastRenderTime)
+ frameTime = currentTime - m_lastRenderTime;
+ m_lastRenderTime = currentTime;
+
+ if (m_fadingTextures.size()) // have some fading images
+ { // anything other than the last old texture needs to be faded out as per usual
+ for (vector<CFadingTexture *>::iterator i = m_fadingTextures.begin(); i != m_fadingTextures.end() - 1;)
+ {
+ if (!RenderFading(*i, frameTime))
+ i = m_fadingTextures.erase(i);
+ else
+ i++;
+ }
+
+ if (m_texture.ReadyToRender() || m_texture.GetFileName().IsEmpty())
+ { // fade out the last one as well
+ if (!RenderFading(m_fadingTextures[m_fadingTextures.size() - 1], frameTime))
+ m_fadingTextures.erase(m_fadingTextures.end() - 1);
+ }
+ else
+ { // keep the last one fading in
+ CFadingTexture *texture = m_fadingTextures[m_fadingTextures.size() - 1];
+ texture->m_fadeTime += frameTime;
+ if (texture->m_fadeTime > m_crossFadeTime)
+ texture->m_fadeTime = m_crossFadeTime;
+ texture->m_texture->SetAlpha(GetFadeLevel(texture->m_fadeTime));
+ texture->m_texture->SetDiffuseColor(m_diffuseColor);
+ texture->m_texture->Render();
+ }
+ }
+
+ if (m_texture.ReadyToRender() || m_texture.GetFileName().IsEmpty())
+ { // fade the new one in
+ m_currentFadeTime += frameTime;
+ if (m_currentFadeTime > m_crossFadeTime || frameTime == 0) // for if we allocate straight away on creation
+ m_currentFadeTime = m_crossFadeTime;
+ }
+ m_texture.SetAlpha(GetFadeLevel(m_currentFadeTime));
+ }
+
+ m_texture.SetDiffuseColor(m_diffuseColor);
+ m_texture.Render();
+
+ CGUIControl::Render();
+}
+
+bool CGUIImage::RenderFading(CGUIImage::CFadingTexture *texture, unsigned int frameTime)
+{
+ assert(texture);
+ if (texture->m_fadeTime <= frameTime)
+ { // time to kill off the texture
+ delete texture;
+ return false;
+ }
+ // render this texture
+ texture->m_fadeTime -= frameTime;
+ texture->m_texture->SetAlpha(GetFadeLevel(texture->m_fadeTime));
+ texture->m_texture->SetDiffuseColor(m_diffuseColor);
+ texture->m_texture->Render();
+ return true;
+}
+
+bool CGUIImage::OnAction(const CAction &action)
+{
+ return false;
+}
+
+bool CGUIImage::OnMessage(CGUIMessage& message)
+{
+ if (message.GetMessage() == GUI_MSG_REFRESH_THUMBS)
+ {
+ if (!m_info.IsConstant())
+ FreeTextures(true); // true as we want to free the texture immediately
+ return true;
+ }
+ return CGUIControl::OnMessage(message);
+}
+
+void CGUIImage::AllocResources()
+{
+ if (m_texture.GetFileName().IsEmpty())
+ return;
+
+ CGUIControl::AllocResources();
+ m_texture.AllocResources();
+}
+
+void CGUIImage::FreeTextures(bool immediately /* = false */)
+{
+ m_texture.FreeResources(immediately);
+ for (unsigned int i = 0; i < m_fadingTextures.size(); i++)
+ delete m_fadingTextures[i];
+ m_fadingTextures.clear();
+}
+
+void CGUIImage::FreeResources()
+{
+ FreeTextures();
+ CGUIControl::FreeResources();
+}
+
+// WORKAROUND - we are currently resetting all animations when this is called, which shouldn't be the case
+// see CGUIControl::FreeResources() - this needs remedying.
+void CGUIImage::FreeResourcesButNotAnims()
+{
+ FreeTextures();
+ m_bAllocated=false;
+ m_hasRendered = false;
+}
+
+void CGUIImage::DynamicResourceAlloc(bool bOnOff)
+{
+ m_bDynamicResourceAlloc = bOnOff;
+ m_texture.DynamicResourceAlloc(bOnOff);
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+}
+
+bool CGUIImage::CanFocus() const
+{
+ return false;
+}
+
+float CGUIImage::GetTextureWidth() const
+{
+ return m_texture.GetTextureWidth();
+}
+
+float CGUIImage::GetTextureHeight() const
+{
+ return m_texture.GetTextureHeight();
+}
+
+const CStdString &CGUIImage::GetFileName() const
+{
+ return m_texture.GetFileName();
+}
+
+void CGUIImage::SetAspectRatio(const CAspectRatio &aspect)
+{
+ m_texture.SetAspectRatio(aspect);
+}
+
+void CGUIImage::SetCrossFade(unsigned int time)
+{
+ m_crossFadeTime = time;
+ if (!m_crossFadeTime && m_texture.IsLazyLoaded() && !m_info.GetFallback().IsEmpty())
+ m_crossFadeTime = 1;
+}
+
+void CGUIImage::SetFileName(const CStdString& strFileName, bool setConstant)
+{
+ if (setConstant)
+ m_info.SetLabel(strFileName, "");
+
+ if (m_crossFadeTime)
+ {
+ // set filename on the next texture
+ if (m_currentTexture.Equals(strFileName))
+ return; // nothing to do - we already have this image
+
+ if (m_texture.ReadyToRender() || m_texture.GetFileName().IsEmpty())
+ { // save the current image
+ m_fadingTextures.push_back(new CFadingTexture(m_texture, m_currentFadeTime));
+ }
+ m_currentFadeTime = 0;
+ }
+ if (!m_currentTexture.Equals(strFileName))
+ { // texture is changing - attempt to load it, and save the name in m_currentTexture.
+ // we'll check whether it loaded or not in Render()
+ m_currentTexture = strFileName;
+ m_texture.SetFileName(m_currentTexture);
+ }
+}
+
+#ifdef _DEBUG
+void CGUIImage::DumpTextureUse()
+{
+ if (m_texture.IsAllocated())
+ {
+ if (GetID())
+ CLog::Log(LOGDEBUG, "Image control %u using texture %s",
+ GetID(), m_texture.GetFileName().c_str());
+ else
+ CLog::Log(LOGDEBUG, "Using texture %s", m_texture.GetFileName().c_str());
+ }
+}
+#endif
+
+void CGUIImage::SetWidth(float width)
+{
+ m_texture.SetWidth(width);
+ CGUIControl::SetWidth(m_texture.GetWidth());
+}
+
+void CGUIImage::SetHeight(float height)
+{
+ m_texture.SetHeight(height);
+ CGUIControl::SetHeight(m_texture.GetHeight());
+}
+
+void CGUIImage::SetPosition(float posX, float posY)
+{
+ m_texture.SetPosition(posX, posY);
+ CGUIControl::SetPosition(posX, posY);
+}
+
+void CGUIImage::SetInfo(const CGUIInfoLabel &info)
+{
+ m_info = info;
+ // a constant image never needs updating
+ if (m_info.IsConstant())
+ m_texture.SetFileName(m_info.GetLabel(0));
+}
+
+unsigned char CGUIImage::GetFadeLevel(unsigned int time) const
+{
+ float amount = (float)time / m_crossFadeTime;
+ // we want a semi-transparent image, so we need to use a more complicated
+ // fade technique. Assuming a black background (not generally true, but still...)
+ // we have
+ // b(t) = [a - b(1-t)*a] / a*(1-b(1-t)*a),
+ // where a = alpha, and b(t):[0,1] -> [0,1] is the blend function.
+ // solving, we get
+ // b(t) = [1 - (1-a)^t] / a
+ const float alpha = 0.7f;
+ return (unsigned char)(255.0f * (1 - pow(1-alpha, amount))/alpha);
+}
+
+CStdString CGUIImage::GetDescription(void) const
+{
+ return GetFileName();
+}
+
diff --git a/guilib/GUIImage.h b/guilib/GUIImage.h
new file mode 100644
index 0000000000..cc9651c9e2
--- /dev/null
+++ b/guilib/GUIImage.h
@@ -0,0 +1,119 @@
+/*!
+\file guiImage.h
+\brief
+*/
+
+#ifndef GUILIB_GUIIMAGECONTROL_H
+#define GUILIB_GUIIMAGECONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+#include "GUITexture.h"
+#include "GUILabelControl.h" // for CGUIInfoLabel
+
+/*!
+ \ingroup controls
+ \brief
+ */
+
+class CGUIImage : public CGUIControl
+{
+public:
+ class CFadingTexture
+ {
+ public:
+ CFadingTexture(const CGUITexture &texture, unsigned int fadeTime)
+ {
+ // create a copy of our texture, and allocate resources
+ m_texture = new CGUITexture(texture);
+ m_texture->AllocResources();
+ m_fadeTime = fadeTime;
+ m_fading = false;
+ };
+ ~CFadingTexture()
+ {
+ m_texture->FreeResources();
+ delete m_texture;
+ };
+
+ CGUITexture *m_texture; ///< texture to fade out
+ unsigned int m_fadeTime; ///< time to fade out (ms)
+ bool m_fading; ///< whether we're fading out
+ };
+
+ CGUIImage(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& texture);
+ CGUIImage(const CGUIImage &left);
+ virtual ~CGUIImage(void);
+ virtual CGUIImage *Clone() const { return new CGUIImage(*this); };
+
+ virtual void Render();
+ virtual void UpdateVisibility(const CGUIListItem *item = NULL);
+ virtual bool OnAction(const CAction &action) ;
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual bool IsDynamicallyAllocated() { return m_bDynamicResourceAlloc; };
+ virtual bool CanFocus() const;
+ virtual void UpdateInfo(const CGUIListItem *item = NULL);
+
+ virtual void SetInfo(const CGUIInfoLabel &info);
+ virtual void SetFileName(const CStdString& strFileName, bool setConstant = false);
+ virtual void SetAspectRatio(const CAspectRatio &aspect);
+ virtual void SetWidth(float width);
+ virtual void SetHeight(float height);
+ virtual void SetPosition(float posX, float posY);
+ virtual CStdString GetDescription() const;
+ void SetCrossFade(unsigned int time);
+
+ const CStdString& GetFileName() const;
+ float GetTextureWidth() const;
+ float GetTextureHeight() const;
+
+#ifdef _DEBUG
+ virtual void DumpTextureUse();
+#endif
+protected:
+ virtual void AllocateOnDemand();
+ virtual void FreeTextures(bool immediately = false);
+ void FreeResourcesButNotAnims();
+ unsigned char GetFadeLevel(unsigned int time) const;
+ bool RenderFading(CFadingTexture *texture, unsigned int frameTime);
+
+ bool m_bDynamicResourceAlloc;
+
+ // border + conditional info
+ CTextureInfo m_image;
+ CGUIInfoLabel m_info;
+
+ CGUITexture m_texture;
+ std::vector<CFadingTexture *> m_fadingTextures;
+ CStdString m_currentTexture;
+
+ unsigned int m_crossFadeTime;
+ unsigned int m_currentFadeTime;
+ unsigned int m_lastRenderTime;
+};
+#endif
diff --git a/guilib/GUIIncludes.cpp b/guilib/GUIIncludes.cpp
new file mode 100644
index 0000000000..e88f3ad6b0
--- /dev/null
+++ b/guilib/GUIIncludes.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIIncludes.h"
+#include "SkinInfo.h"
+#include "utils/GUIInfoManager.h"
+#include "utils/log.h"
+#include "tinyXML/tinyxml.h"
+
+using namespace std;
+
+CGUIIncludes::CGUIIncludes()
+{
+}
+
+CGUIIncludes::~CGUIIncludes()
+{
+}
+
+void CGUIIncludes::ClearIncludes()
+{
+ m_includes.clear();
+ m_defaults.clear();
+ m_constants.clear();
+ m_files.clear();
+}
+
+bool CGUIIncludes::LoadIncludes(const CStdString &includeFile)
+{
+ // check to see if we already have this loaded
+ if (HasIncludeFile(includeFile))
+ return true;
+
+ TiXmlDocument doc;
+ if (!doc.LoadFile(includeFile))
+ {
+ CLog::Log(LOGINFO, "Error loading includes.xml file (%s): %s (row=%i, col=%i)", includeFile.c_str(), doc.ErrorDesc(), doc.ErrorRow(), doc.ErrorCol());
+ return false;
+ }
+ // success, load the tags
+ if (LoadIncludesFromXML(doc.RootElement()))
+ {
+ m_files.push_back(includeFile);
+ return true;
+ }
+ return false;
+}
+
+bool CGUIIncludes::LoadIncludesFromXML(const TiXmlElement *root)
+{
+ if (!root || strcmpi(root->Value(), "includes"))
+ {
+ CLog::Log(LOGERROR, "Skin includes must start with the <includes> tag");
+ return false;
+ }
+ const TiXmlElement* node = root->FirstChildElement("include");
+ while (node)
+ {
+ if (node->Attribute("name") && node->FirstChild())
+ {
+ CStdString tagName = node->Attribute("name");
+ m_includes.insert(pair<CStdString, TiXmlElement>(tagName, *node));
+ }
+ else if (node->Attribute("file"))
+ { // load this file in as well
+ RESOLUTION res;
+ LoadIncludes(g_SkinInfo.GetSkinPath(node->Attribute("file"), &res));
+ }
+ node = node->NextSiblingElement("include");
+ }
+ // now defaults
+ node = root->FirstChildElement("default");
+ while (node)
+ {
+ if (node->Attribute("type") && node->FirstChild())
+ {
+ CStdString tagName = node->Attribute("type");
+ m_defaults.insert(pair<CStdString, TiXmlElement>(tagName, *node));
+ }
+ node = node->NextSiblingElement("default");
+ }
+ // and finally constants
+ node = root->FirstChildElement("constant");
+ while (node)
+ {
+ if (node->Attribute("name") && node->FirstChild())
+ {
+ CStdString tagName = node->Attribute("name");
+ m_constants.insert(pair<CStdString, float>(tagName, (float)atof(node->FirstChild()->Value())));
+ }
+ node = node->NextSiblingElement("constant");
+ }
+ return true;
+}
+
+bool CGUIIncludes::HasIncludeFile(const CStdString &file) const
+{
+ for (iFiles it = m_files.begin(); it != m_files.end(); ++it)
+ if (*it == file) return true;
+ return false;
+}
+
+void CGUIIncludes::ResolveIncludes(TiXmlElement *node, const CStdString &type)
+{
+ // we have a node, find any <include file="fileName">tagName</include> tags and replace
+ // recursively with their real includes
+ if (!node) return;
+
+ // First add the defaults if this is for a control
+ if (!type.IsEmpty())
+ { // resolve defaults
+ map<CStdString, TiXmlElement>::iterator it = m_defaults.find(type);
+ if (it != m_defaults.end())
+ {
+ const TiXmlElement &element = (*it).second;
+ const TiXmlElement *tag = element.FirstChildElement();
+ while (tag)
+ {
+ // we insert at the end of block
+ node->InsertEndChild(*tag);
+ tag = tag->NextSiblingElement();
+ }
+ }
+ }
+ TiXmlElement *include = node->FirstChildElement("include");
+ while (include && include->FirstChild())
+ {
+ // have an include tag - grab it's tag name and replace it with the real tag contents
+ const char *file = include->Attribute("file");
+ if (file)
+ { // we need to load this include from the alternative file
+ RESOLUTION res;
+ LoadIncludes(g_SkinInfo.GetSkinPath(file, &res));
+ }
+ const char *condition = include->Attribute("condition");
+ if (condition)
+ { // check this condition
+ if (!g_infoManager.GetBool(g_infoManager.TranslateString(condition)))
+ {
+ include = include->NextSiblingElement("include");
+ continue;
+ }
+ }
+ CStdString tagName = include->FirstChild()->Value();
+ map<CStdString, TiXmlElement>::iterator it = m_includes.find(tagName);
+ if (it != m_includes.end())
+ { // found the tag(s) to include - let's replace it
+ const TiXmlElement &element = (*it).second;
+ const TiXmlElement *tag = element.FirstChildElement();
+ while (tag)
+ {
+ // we insert before the <include> element to keep the correct
+ // order (we render in the order given in the xml file)
+ node->InsertBeforeChild(include, *tag);
+ tag = tag->NextSiblingElement();
+ }
+ // remove the <include>tagName</include> element
+ node->RemoveChild(include);
+ include = node->FirstChildElement("include");
+ }
+ else
+ { // invalid include
+ CLog::Log(LOGWARNING, "Skin has invalid include: %s", tagName.c_str());
+ include = include->NextSiblingElement("include");
+ }
+ }
+}
+
+bool CGUIIncludes::ResolveConstant(const CStdString &constant, float &value)
+{
+ map<CStdString, float>::iterator it = m_constants.find(constant);
+ if (it == m_constants.end())
+ value = (float)atof(constant.c_str());
+ else
+ value = it->second;
+ return true;
+}
+
diff --git a/guilib/GUIIncludes.h b/guilib/GUIIncludes.h
new file mode 100644
index 0000000000..5cf68eb631
--- /dev/null
+++ b/guilib/GUIIncludes.h
@@ -0,0 +1,51 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "StdString.h"
+
+#include <map>
+
+// forward definitions
+class TiXmlElement;
+
+class CGUIIncludes
+{
+public:
+ CGUIIncludes();
+ ~CGUIIncludes();
+
+ void ClearIncludes();
+ bool LoadIncludes(const CStdString &includeFile);
+ void ResolveIncludes(TiXmlElement *node, const CStdString &type);
+ bool ResolveConstant(const CStdString &constant, float &value);
+ bool LoadIncludesFromXML(const TiXmlElement *root);
+
+private:
+ bool HasIncludeFile(const CStdString &includeFile) const;
+ std::map<CStdString, TiXmlElement> m_includes;
+ std::map<CStdString, TiXmlElement> m_defaults;
+ std::map<CStdString, float> m_constants;
+ std::vector<CStdString> m_files;
+ typedef std::vector<CStdString>::const_iterator iFiles;
+};
+
diff --git a/guilib/GUIInfoColor.cpp b/guilib/GUIInfoColor.cpp
new file mode 100644
index 0000000000..42450f54dd
--- /dev/null
+++ b/guilib/GUIInfoColor.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIInfoColor.h"
+#include "utils/CharsetConverter.h"
+#include "utils/GUIInfoManager.h"
+#include "LocalizeStrings.h"
+#include "GUIColorManager.h"
+
+using namespace std;
+
+CGUIInfoBool::CGUIInfoBool(bool value)
+{
+ m_info = 0;
+ m_value = value;
+}
+
+void CGUIInfoBool::Parse(const CStdString &info)
+{
+ m_info = g_infoManager.TranslateString(info);
+ if (m_info == SYSTEM_ALWAYS_TRUE)
+ {
+ m_value = true;
+ m_info = 0;
+ }
+ else if (m_info == SYSTEM_ALWAYS_FALSE)
+ {
+ m_value = false;
+ m_info = 0;
+ }
+ else
+ m_info = g_infoManager.GetBool(m_info);
+}
+
+void CGUIInfoBool::Update(int parentID, const CGUIListItem *item)
+{
+ if (m_info)
+ m_value = g_infoManager.GetBool(m_info, parentID, item);
+}
+
+
+CGUIInfoColor::CGUIInfoColor(uint32_t color)
+{
+ m_color = color;
+ m_info = 0;
+}
+
+const CGUIInfoColor &CGUIInfoColor::operator=(color_t color)
+{
+ m_color = color;
+ m_info = 0;
+ return *this;
+}
+
+const CGUIInfoColor &CGUIInfoColor::operator=(const CGUIInfoColor &color)
+{
+ m_color = color.m_color;
+ m_info = color.m_info;
+ return *this;
+}
+
+void CGUIInfoColor::Update()
+{
+ if (!m_info)
+ return; // no infolabel
+
+ // Expand the infolabel, and then convert it to a color
+ CStdString infoLabel(g_infoManager.GetLabel(m_info));
+ if (!infoLabel.IsEmpty())
+ m_color = g_colorManager.GetColor(infoLabel.c_str());
+ else
+ m_color = 0;
+}
+
+void CGUIInfoColor::Parse(const CStdString &label)
+{
+ // Check for the standard $INFO[] block layout, and strip it if present
+ CStdString label2 = label;
+ if (label.Equals("-", false))
+ return;
+
+ if (label.Left(5).Equals("$INFO", false))
+ label2 = label.Mid(6, label.length()-7);
+
+ m_info = g_infoManager.TranslateString(label2);
+ if (!m_info)
+ m_color = g_colorManager.GetColor(label);
+}
+
diff --git a/guilib/GUIInfoColor.h b/guilib/GUIInfoColor.h
new file mode 100644
index 0000000000..612eefef95
--- /dev/null
+++ b/guilib/GUIInfoColor.h
@@ -0,0 +1,69 @@
+/*!
+\file GUIInfoColor.h
+\brief
+*/
+
+#ifndef GUILIB_GUIINFOCOLOR_H
+#define GUILIB_GUIINFOCOLOR_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "StdString.h"
+
+class CGUIListItem;
+
+class CGUIInfoBool
+{
+public:
+ CGUIInfoBool(bool value = false);
+ operator bool() const { return m_value; };
+
+ void Update(int parentID = 0, const CGUIListItem *item = NULL);
+ void Parse(const CStdString &info);
+private:
+ int m_info;
+ bool m_value;
+};
+
+typedef uint32_t color_t;
+
+class CGUIInfoColor
+{
+public:
+ CGUIInfoColor(color_t color = 0);
+
+ const CGUIInfoColor &operator=(const CGUIInfoColor &color);
+ const CGUIInfoColor &operator=(color_t color);
+ operator color_t() const { return m_color; };
+
+ void Update();
+ void Parse(const CStdString &label);
+
+private:
+ color_t GetColor() const;
+ int m_info;
+ color_t m_color;
+};
+
+#endif
diff --git a/guilib/GUILabelControl.cpp b/guilib/GUILabelControl.cpp
new file mode 100644
index 0000000000..6b4a86f621
--- /dev/null
+++ b/guilib/GUILabelControl.cpp
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUILabelControl.h"
+#include "utils/CharsetConverter.h"
+#include "utils/GUIInfoManager.h"
+#include "utils/log.h"
+#include "GUIListItem.h"
+#include "StringUtils.h"
+
+#include "LocalizeStrings.h" // for CGUIInfoLabel
+
+using namespace std;
+
+CGUIInfoLabel::CGUIInfoLabel()
+{
+}
+
+CGUIInfoLabel::CGUIInfoLabel(const CStdString &label, const CStdString &fallback)
+{
+ SetLabel(label, fallback);
+}
+
+void CGUIInfoLabel::SetLabel(const CStdString &label, const CStdString &fallback)
+{
+ m_fallback = fallback;
+ Parse(label);
+}
+
+CStdString CGUIInfoLabel::GetLabel(int contextWindow, bool preferImage) const
+{
+ CStdString label;
+ for (unsigned int i = 0; i < m_info.size(); i++)
+ {
+ const CInfoPortion &portion = m_info[i];
+ if (portion.m_info)
+ {
+ CStdString infoLabel;
+ if (preferImage)
+ infoLabel = g_infoManager.GetImage(portion.m_info, contextWindow);
+ if (infoLabel.IsEmpty())
+ infoLabel = g_infoManager.GetLabel(portion.m_info, contextWindow);
+ if (!infoLabel.IsEmpty())
+ {
+ label += portion.m_prefix;
+ label += infoLabel;
+ label += portion.m_postfix;
+ }
+ }
+ else
+ { // no info, so just append the prefix
+ label += portion.m_prefix;
+ }
+ }
+ if (label.IsEmpty()) // empty label, use the fallback
+ return m_fallback;
+ return label;
+}
+
+CStdString CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool preferImages) const
+{
+ if (!item->IsFileItem()) return "";
+ CStdString label;
+ for (unsigned int i = 0; i < m_info.size(); i++)
+ {
+ const CInfoPortion &portion = m_info[i];
+ if (portion.m_info)
+ {
+ CStdString infoLabel;
+ if (preferImages)
+ infoLabel = g_infoManager.GetItemImage((const CFileItem *)item, portion.m_info);
+ else
+ infoLabel = g_infoManager.GetItemLabel((const CFileItem *)item, portion.m_info);
+ if (!infoLabel.IsEmpty())
+ {
+ label += portion.m_prefix;
+ label += infoLabel;
+ label += portion.m_postfix;
+ }
+ }
+ else
+ { // no info, so just append the prefix
+ label += portion.m_prefix;
+ }
+ }
+ if (label.IsEmpty())
+ return m_fallback;
+ return label;
+}
+
+bool CGUIInfoLabel::IsEmpty() const
+{
+ return m_info.size() == 0;
+}
+
+bool CGUIInfoLabel::IsConstant() const
+{
+ return m_info.size() == 0 || (m_info.size() == 1 && m_info[0].m_info == 0);
+}
+
+void CGUIInfoLabel::Parse(const CStdString &label)
+{
+ m_info.clear();
+ CStdString work(label);
+ // Step 1: Replace all $LOCALIZE[number] with the real string
+ int pos1 = work.Find("$LOCALIZE[");
+ while (pos1 >= 0)
+ {
+ int pos2 = StringUtils::FindEndBracket(work, '[', ']', pos1 + 10);
+ if (pos2 > pos1)
+ {
+ CStdString left = work.Left(pos1);
+ CStdString right = work.Mid(pos2 + 1);
+ CStdString replace = g_localizeStringsTemp.Get(atoi(work.Mid(pos1 + 10).c_str()));
+ if (replace == "")
+ replace = g_localizeStrings.Get(atoi(work.Mid(pos1 + 10).c_str()));
+ work = left + replace + right;
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "Error parsing label - missing ']'");
+ return;
+ }
+ pos1 = work.Find("$LOCALIZE[", pos1);
+ }
+ // Step 2: Find all $INFO[info,prefix,postfix] blocks
+ pos1 = work.Find("$INFO[");
+ while (pos1 >= 0)
+ {
+ // output the first block (contents before first $INFO)
+ if (pos1 > 0)
+ m_info.push_back(CInfoPortion(0, work.Left(pos1), ""));
+
+ // ok, now decipher the $INFO block
+ int pos2 = StringUtils::FindEndBracket(work, '[', ']', pos1 + 6);
+ if (pos2 > pos1)
+ {
+ // decipher the block
+ CStdString block = work.Mid(pos1 + 6, pos2 - pos1 - 6);
+ CStdStringArray params;
+ StringUtils::SplitString(block, ",", params);
+ int info = g_infoManager.TranslateString(params[0]);
+ CStdString prefix, postfix;
+ if (params.size() > 1)
+ prefix = params[1];
+ if (params.size() > 2)
+ postfix = params[2];
+ m_info.push_back(CInfoPortion(info, prefix, postfix));
+ // and delete it from our work string
+ work = work.Mid(pos2 + 1);
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "Error parsing label - missing ']'");
+ return;
+ }
+ pos1 = work.Find("$INFO[");
+ }
+ // add any last block
+ if (!work.IsEmpty())
+ m_info.push_back(CInfoPortion(0, work, ""));
+}
+
+CGUIInfoLabel::CInfoPortion::CInfoPortion(int info, const CStdString &prefix, const CStdString &postfix)
+{
+ m_info = info;
+ m_prefix = prefix;
+ m_postfix = postfix;
+ // filter our prefix and postfix for comma's
+ m_prefix.Replace("$COMMA", ",");
+ m_postfix.Replace("$COMMA", ",");
+ m_prefix.Replace("$LBRACKET", "["); m_prefix.Replace("$RBRACKET", "]");
+ m_postfix.Replace("$LBRACKET", "["); m_postfix.Replace("$RBRACKET", "]");
+}
+
+CStdString CGUIInfoLabel::GetLabel(const CStdString &label, bool preferImage)
+{ // translate the label
+ CGUIInfoLabel info(label, "");
+ return info.GetLabel(0, preferImage);
+}
+
+CGUILabelControl::CGUILabelControl(int parentID, int controlID, float posX, float posY, float width, float height, const CLabelInfo& labelInfo, bool wrapMultiLine, bool bHasPath)
+ : CGUIControl(parentID, controlID, posX, posY, width, height), m_textLayout(labelInfo.font, wrapMultiLine)
+{
+ m_bHasPath = bHasPath;
+ m_iCursorPos = 0;
+ m_label = labelInfo;
+ m_bShowCursor = false;
+ m_dwCounter = 0;
+ ControlType = GUICONTROL_LABEL;
+ m_ScrollInsteadOfTruncate = false;
+ m_startHighlight = m_endHighlight = 0;
+}
+
+CGUILabelControl::~CGUILabelControl(void)
+{
+}
+
+void CGUILabelControl::ShowCursor(bool bShow)
+{
+ m_bShowCursor = bShow;
+}
+
+void CGUILabelControl::SetCursorPos(int iPos)
+{
+ CStdString label = m_infoLabel.GetLabel(m_parentID);
+ if (iPos > (int)label.length()) iPos = label.length();
+ if (iPos < 0) iPos = 0;
+ m_iCursorPos = iPos;
+}
+
+void CGUILabelControl::SetInfo(const CGUIInfoLabel &infoLabel)
+{
+ m_infoLabel = infoLabel;
+}
+
+void CGUILabelControl::UpdateColors()
+{
+ m_label.UpdateColors();
+ CGUIControl::UpdateColors();
+}
+
+void CGUILabelControl::UpdateInfo(const CGUIListItem *item)
+{
+ CStdString label(m_infoLabel.GetLabel(m_parentID));
+
+ if (m_bShowCursor)
+ { // cursor location assumes utf16 text, so deal with that (inefficient, but it's not as if it's a high-use area
+ // virtual keyboard only)
+ CStdStringW utf16;
+ g_charsetConverter.utf8ToW(label, utf16);
+ CStdStringW col;
+ if ((++m_dwCounter % 50) > 25)
+ col.Format(L"|");
+ else
+ col.Format(L"[COLOR %x]|[/COLOR]", 0x1000000);
+ utf16.Insert(m_iCursorPos, col);
+ g_charsetConverter.wToUTF8(utf16, label);
+ }
+ else if (m_startHighlight || m_endHighlight)
+ { // this is only used for times/dates, so working in ascii (utf8) is fine
+ CStdString colorLabel;
+ colorLabel.Format("[COLOR %x]%s[/COLOR]%s[COLOR %x]%s[/COLOR]", (color_t)m_label.disabledColor, label.Left(m_startHighlight),
+ label.Mid(m_startHighlight, m_endHighlight - m_startHighlight), (color_t)m_label.disabledColor, label.Mid(m_endHighlight));
+ label = colorLabel;
+ }
+
+ if (m_textLayout.Update(label, m_width))
+ { // reset the scrolling as we have a new label
+ m_ScrollInfo.Reset();
+ }
+}
+
+void CGUILabelControl::Render()
+{
+ // check for scrolling
+ bool bNormalDraw = true;
+ if (m_ScrollInsteadOfTruncate && m_width > 0 && !IsDisabled())
+ { // ignore align center - just use align left/right
+ float width, height;
+ m_textLayout.GetTextExtent(width, height);
+ if (width > m_width)
+ { // need to scroll - set the viewport. Should be set just using the height of the text
+ bNormalDraw = false;
+ float fPosX = m_posX;
+ if (m_label.align & XBFONT_RIGHT)
+ fPosX -= m_width;
+ float fPosY = m_posY;
+ if (m_label.align & XBFONT_CENTER_Y)
+ fPosY += m_height * 0.5f;
+
+ m_textLayout.RenderScrolling(fPosX, fPosY, m_label.angle, m_label.textColor, m_label.shadowColor, (m_label.align & ~3), m_width, m_ScrollInfo);
+ }
+ }
+ if (bNormalDraw)
+ {
+ float fPosX = m_posX;
+ if (m_label.align & XBFONT_CENTER_X)
+ fPosX += m_width * 0.5f;
+
+ float fPosY = m_posY;
+ if (m_label.align & XBFONT_CENTER_Y)
+ fPosY += m_height * 0.5f;
+
+ if (IsDisabled())
+ m_textLayout.Render(fPosX, fPosY, m_label.angle, m_label.disabledColor, m_label.shadowColor, m_label.align | XBFONT_TRUNCATED, m_width, true);
+ else
+ m_textLayout.Render(fPosX, fPosY, m_label.angle, m_label.textColor, m_label.shadowColor, m_label.align | XBFONT_TRUNCATED, m_width);
+ }
+ CGUIControl::Render();
+}
+
+
+bool CGUILabelControl::CanFocus() const
+{
+ return false;
+}
+
+void CGUILabelControl::SetLabel(const string &strLabel)
+{
+ // shorten the path label
+ if ( m_bHasPath )
+ m_infoLabel.SetLabel(ShortenPath(strLabel), "");
+ else // parse the label for info tags
+ m_infoLabel.SetLabel(strLabel, "");
+ m_ScrollInfo.Reset();
+ if (m_iCursorPos > (int)strLabel.size())
+ m_iCursorPos = strLabel.size();
+}
+
+void CGUILabelControl::SetWidthControl(bool bScroll, int scrollSpeed)
+{
+ m_ScrollInsteadOfTruncate = bScroll;
+ m_ScrollInfo.SetSpeed(scrollSpeed);
+ m_ScrollInfo.Reset();
+}
+
+void CGUILabelControl::SetAlignment(uint32_t align)
+{
+ m_label.align = align;
+}
+
+bool CGUILabelControl::OnMessage(CGUIMessage& message)
+{
+ if ( message.GetControlId() == GetID() )
+ {
+ if (message.GetMessage() == GUI_MSG_LABEL_SET)
+ {
+ SetLabel(message.GetLabel());
+ return true;
+ }
+ }
+
+ return CGUIControl::OnMessage(message);
+}
+
+CStdString CGUILabelControl::ShortenPath(const CStdString &path)
+{
+ if (!m_label.font || m_width == 0 || path.IsEmpty())
+ return path;
+
+ char cDelim = '\0';
+ size_t nPos;
+
+ nPos = path.find_last_of( '\\' );
+ if ( nPos != std::string::npos )
+ cDelim = '\\';
+ else
+ {
+ nPos = path.find_last_of( '/' );
+ if ( nPos != std::string::npos )
+ cDelim = '/';
+ }
+ if ( cDelim == '\0' )
+ return path;
+
+ CStdString workPath(path);
+ // remove trailing slashes
+ if (workPath.size() > 3)
+ if (workPath.Right(3).Compare("://") != 0 && workPath.Right(2).Compare(":\\") != 0)
+ if (nPos == workPath.size() - 1)
+ {
+ workPath.erase(workPath.size() - 1);
+ nPos = workPath.find_last_of( cDelim );
+ }
+
+ float fTextHeight, fTextWidth;
+ m_textLayout.Update(workPath);
+ m_textLayout.GetTextExtent(fTextWidth, fTextHeight);
+
+ while ( fTextWidth > m_width )
+ {
+ size_t nGreaterDelim = workPath.find_last_of( cDelim, nPos );
+ if (nGreaterDelim == std::string::npos)
+ break;
+
+ nPos = workPath.find_last_of( cDelim, nGreaterDelim - 1 );
+ if ( nPos == std::string::npos )
+ break;
+
+ workPath.replace( nPos + 1, nGreaterDelim - nPos - 1, "..." );
+
+ m_textLayout.Update(workPath);
+ m_textLayout.GetTextExtent(fTextWidth, fTextHeight);
+ }
+ return workPath;
+}
+
+void CGUILabelControl::SetTruncate(bool bTruncate)
+{
+ if (bTruncate)
+ m_label.align |= XBFONT_TRUNCATED;
+ else
+ m_label.align &= ~XBFONT_TRUNCATED;
+}
+
+void CGUILabelControl::SetHighlight(unsigned int start, unsigned int end)
+{
+ m_startHighlight = start;
+ m_endHighlight = end;
+}
+
+CStdString CGUILabelControl::GetDescription() const
+{
+ return m_infoLabel.GetLabel(m_parentID);
+}
diff --git a/guilib/GUILabelControl.h b/guilib/GUILabelControl.h
new file mode 100644
index 0000000000..052c635994
--- /dev/null
+++ b/guilib/GUILabelControl.h
@@ -0,0 +1,118 @@
+/*!
+\file GUILabelControl.h
+\brief
+*/
+
+#ifndef GUILIB_GUILABELCONTROL_H
+#define GUILIB_GUILABELCONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+#include "GUITextLayout.h"
+
+class CGUIListItem;
+
+class CGUIInfoLabel
+{
+public:
+ CGUIInfoLabel();
+ CGUIInfoLabel(const CStdString &label, const CStdString &fallback = "");
+
+ void SetLabel(const CStdString &label, const CStdString &fallback);
+ CStdString GetLabel(int contextWindow, bool preferImage = false) const;
+ CStdString GetItemLabel(const CGUIListItem *item, bool preferImage = false) const;
+ bool IsConstant() const;
+ bool IsEmpty() const;
+
+ const CStdString GetFallback() const { return m_fallback; };
+
+ static CStdString GetLabel(const CStdString &label, bool preferImage = false);
+private:
+ void Parse(const CStdString &label);
+
+ class CInfoPortion
+ {
+ public:
+ CInfoPortion(int info, const CStdString &prefix, const CStdString &postfix);
+ int m_info;
+ CStdString m_prefix;
+ CStdString m_postfix;
+ };
+
+ CStdString m_fallback;
+ std::vector<CInfoPortion> m_info;
+};
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUILabelControl :
+ public CGUIControl
+{
+public:
+ CGUILabelControl(int parentID, int controlID, float posX, float posY, float width, float height, const CLabelInfo& labelInfo, bool wrapMultiLine, bool bHasPath);
+ virtual ~CGUILabelControl(void);
+ virtual CGUILabelControl *Clone() const { return new CGUILabelControl(*this); };
+
+ virtual void Render();
+ virtual void UpdateInfo(const CGUIListItem *item = NULL);
+ virtual bool CanFocus() const;
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual CStdString GetDescription() const;
+
+ const CLabelInfo& GetLabelInfo() const { return m_label; };
+ void SetLabel(const std::string &strLabel);
+ void ShowCursor(bool bShow = true);
+ void SetCursorPos(int iPos);
+ int GetCursorPos() const { return m_iCursorPos;};
+ void SetInfo(const CGUIInfoLabel&labelInfo);
+ void SetWidthControl(bool bScroll, int scrollSpeed);
+ void SetTruncate(bool bTruncate);
+ void SetAlignment(uint32_t align);
+ void SetHighlight(unsigned int start, unsigned int end);
+
+protected:
+ void UpdateColors();
+ CStdString ShortenPath(const CStdString &path);
+
+ CLabelInfo m_label;
+ CGUITextLayout m_textLayout;
+
+ bool m_bHasPath;
+ bool m_bShowCursor;
+ int m_iCursorPos;
+ unsigned int m_dwCounter;
+ // stuff for scrolling
+ bool m_ScrollInsteadOfTruncate;
+ CScrollInfo m_ScrollInfo;
+
+ // multi-info stuff
+ CGUIInfoLabel m_infoLabel;
+
+ unsigned int m_startHighlight;
+ unsigned int m_endHighlight;
+};
+#endif
diff --git a/guilib/GUIListContainer.cpp b/guilib/GUIListContainer.cpp
new file mode 100644
index 0000000000..7de8631e6c
--- /dev/null
+++ b/guilib/GUIListContainer.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIListContainer.h"
+#include "GUIListItem.h"
+#include "GUIInfoManager.h"
+#include "Key.h"
+
+CGUIListContainer::CGUIListContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, int scrollTime, int preloadItems)
+ : CGUIBaseContainer(parentID, controlID, posX, posY, width, height, orientation, scrollTime, preloadItems)
+{
+ ControlType = GUICONTAINER_LIST;
+ m_type = VIEW_TYPE_LIST;
+}
+
+CGUIListContainer::~CGUIListContainer(void)
+{
+}
+
+bool CGUIListContainer::OnAction(const CAction &action)
+{
+ switch (action.id)
+ {
+ case ACTION_PAGE_UP:
+ {
+ if (m_offset == 0)
+ { // already on the first page, so move to the first item
+ SetCursor(0);
+ }
+ else
+ { // scroll up to the previous page
+ Scroll( -m_itemsPerPage);
+ }
+ return true;
+ }
+ break;
+ case ACTION_PAGE_DOWN:
+ {
+ if (m_offset == (int)m_items.size() - m_itemsPerPage || (int)m_items.size() < m_itemsPerPage)
+ { // already at the last page, so move to the last item.
+ SetCursor(m_items.size() - m_offset - 1);
+ }
+ else
+ { // scroll down to the next page
+ Scroll(m_itemsPerPage);
+ }
+ return true;
+ }
+ break;
+ // smooth scrolling (for analog controls)
+ case ACTION_SCROLL_UP:
+ {
+ m_analogScrollCount += action.amount1 * action.amount1;
+ bool handled = false;
+ while (m_analogScrollCount > 0.4)
+ {
+ handled = true;
+ m_analogScrollCount -= 0.4f;
+ if (m_offset > 0 && m_cursor <= m_itemsPerPage / 2)
+ {
+ Scroll(-1);
+ }
+ else if (m_cursor > 0)
+ {
+ SetCursor(m_cursor - 1);
+ }
+ }
+ return handled;
+ }
+ break;
+ case ACTION_SCROLL_DOWN:
+ {
+ m_analogScrollCount += action.amount1 * action.amount1;
+ bool handled = false;
+ while (m_analogScrollCount > 0.4)
+ {
+ handled = true;
+ m_analogScrollCount -= 0.4f;
+ if (m_offset + m_itemsPerPage < (int)m_items.size() && m_cursor >= m_itemsPerPage / 2)
+ {
+ Scroll(1);
+ }
+ else if (m_cursor < m_itemsPerPage - 1 && m_offset + m_cursor < (int)m_items.size() - 1)
+ {
+ SetCursor(m_cursor + 1);
+ }
+ }
+ return handled;
+ }
+ break;
+ }
+ return CGUIBaseContainer::OnAction(action);
+}
+
+bool CGUIListContainer::OnMessage(CGUIMessage& message)
+{
+ if (message.GetControlId() == GetID() )
+ {
+ if (message.GetMessage() == GUI_MSG_LABEL_RESET)
+ {
+ SetCursor(0);
+ }
+ else if (message.GetMessage() == GUI_MSG_ITEM_SELECT)
+ {
+ SelectItem(message.GetParam1());
+ return true;
+ }
+ else if (message.GetMessage() == GUI_MSG_SETFOCUS)
+ {
+ if (message.GetParam1()) // subfocus item is specified, so set the offset appropriately
+ m_cursor = (int)message.GetParam1() - 1;
+ }
+ }
+ return CGUIBaseContainer::OnMessage(message);
+}
+
+bool CGUIListContainer::MoveUp(bool wrapAround)
+{
+ if (m_cursor > 0)
+ {
+ SetCursor(m_cursor - 1);
+ }
+ else if (m_cursor == 0 && m_offset)
+ {
+ ScrollToOffset(m_offset - 1);
+ }
+ else if (wrapAround)
+ {
+ if (m_items.size() > 0)
+ { // move 2 last item in list, and set our container moving up
+ int offset = m_items.size() - m_itemsPerPage;
+ if (offset < 0) offset = 0;
+ SetCursor(m_items.size() - offset - 1);
+ ScrollToOffset(offset);
+ g_infoManager.SetContainerMoving(GetID(), -1);
+ }
+ }
+ else
+ return false;
+ return true;
+}
+
+bool CGUIListContainer::MoveDown(bool wrapAround)
+{
+ if (m_offset + m_cursor + 1 < (int)m_items.size())
+ {
+ if (m_cursor + 1 < m_itemsPerPage)
+ {
+ SetCursor(m_cursor + 1);
+ }
+ else
+ {
+ ScrollToOffset(m_offset + 1);
+ }
+ }
+ else if(wrapAround)
+ { // move first item in list, and set our container moving in the "down" direction
+ SetCursor(0);
+ ScrollToOffset(0);
+ g_infoManager.SetContainerMoving(GetID(), 1);
+ }
+ else
+ return false;
+ return true;
+}
+
+// scrolls the said amount
+void CGUIListContainer::Scroll(int amount)
+{
+ // increase or decrease the offset
+ int offset = m_offset + amount;
+ if (offset > (int)m_items.size() - m_itemsPerPage)
+ {
+ offset = m_items.size() - m_itemsPerPage;
+ }
+ if (offset < 0) offset = 0;
+ ScrollToOffset(offset);
+}
+
+void CGUIListContainer::ValidateOffset()
+{ // first thing is we check the range of m_offset
+ if (!m_layout) return;
+ if (m_offset > (int)m_items.size() - m_itemsPerPage)
+ {
+ m_offset = m_items.size() - m_itemsPerPage;
+ m_scrollOffset = m_offset * m_layout->Size(m_orientation);
+ }
+ if (m_offset < 0)
+ {
+ m_offset = 0;
+ m_scrollOffset = 0;
+ }
+}
+
+void CGUIListContainer::SetCursor(int cursor)
+{
+ if (cursor > m_itemsPerPage - 1) cursor = m_itemsPerPage - 1;
+ if (cursor < 0) cursor = 0;
+ if (!m_wasReset)
+ g_infoManager.SetContainerMoving(GetID(), cursor - m_cursor);
+ m_cursor = cursor;
+}
+
+void CGUIListContainer::SelectItem(int item)
+{
+ // Check that m_offset is valid
+ ValidateOffset();
+ // only select an item if it's in a valid range
+ if (item >= 0 && item < (int)m_items.size())
+ {
+ // Select the item requested
+ if (item >= m_offset && item < m_offset + m_itemsPerPage)
+ { // the item is on the current page, so don't change it.
+ SetCursor(item - m_offset);
+ }
+ else if (item < m_offset)
+ { // item is on a previous page - make it the first item on the page
+ SetCursor(0);
+ ScrollToOffset(item);
+ }
+ else // (item >= m_offset+m_itemsPerPage)
+ { // item is on a later page - make it the last item on the page
+ SetCursor(m_itemsPerPage - 1);
+ ScrollToOffset(item - m_cursor);
+ }
+ }
+}
+//#ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY
+CGUIListContainer::CGUIListContainer(int parentID, int controlID, float posX, float posY, float width, float height,
+ const CLabelInfo& labelInfo, const CLabelInfo& labelInfo2,
+ const CTextureInfo& textureButton, const CTextureInfo& textureButtonFocus,
+ float textureHeight, float itemWidth, float itemHeight, float spaceBetweenItems)
+: CGUIBaseContainer(parentID, controlID, posX, posY, width, height, VERTICAL, 200, 0)
+{
+ CGUIListItemLayout layout;
+ layout.CreateListControlLayouts(width, textureHeight + spaceBetweenItems, false, labelInfo, labelInfo2, textureButton, textureButtonFocus, textureHeight, itemWidth, itemHeight, 0, 0);
+ m_layouts.push_back(layout);
+ CStdString condition;
+ condition.Format("control.hasfocus(%i)", controlID);
+ CStdString condition2 = "!" + condition;
+ CGUIListItemLayout focusLayout;
+ focusLayout.CreateListControlLayouts(width, textureHeight + spaceBetweenItems, true, labelInfo, labelInfo2, textureButton, textureButtonFocus, textureHeight, itemWidth, itemHeight, g_infoManager.TranslateString(condition2), g_infoManager.TranslateString(condition));
+ m_focusedLayouts.push_back(focusLayout);
+ m_height = floor(m_height / (textureHeight + spaceBetweenItems)) * (textureHeight + spaceBetweenItems);
+ ControlType = GUICONTAINER_LIST;
+}
+//#endif
+
+bool CGUIListContainer::HasNextPage() const
+{
+ return (m_offset != (int)m_items.size() - m_itemsPerPage && (int)m_items.size() >= m_itemsPerPage);
+}
+
+bool CGUIListContainer::HasPreviousPage() const
+{
+ return (m_offset > 0);
+}
diff --git a/guilib/GUIListContainer.h b/guilib/GUIListContainer.h
new file mode 100644
index 0000000000..176183cb1a
--- /dev/null
+++ b/guilib/GUIListContainer.h
@@ -0,0 +1,62 @@
+/*!
+\file GUIListContainer.h
+\brief
+*/
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIBaseContainer.h"
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIListContainer : public CGUIBaseContainer
+{
+public:
+ CGUIListContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, int scrollTime, int preloadItems);
+//#ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY
+ CGUIListContainer(int parentID, int controlID, float posX, float posY, float width, float height,
+ const CLabelInfo& labelInfo, const CLabelInfo& labelInfo2,
+ const CTextureInfo& textureButton, const CTextureInfo& textureButtonFocus,
+ float textureHeight, float itemWidth, float itemHeight, float spaceBetweenItems);
+//#endif
+ virtual ~CGUIListContainer(void);
+ virtual CGUIListContainer *Clone() const { return new CGUIListContainer(*this); };
+
+ virtual bool OnAction(const CAction &action);
+ virtual bool OnMessage(CGUIMessage& message);
+
+ virtual bool HasNextPage() const;
+ virtual bool HasPreviousPage() const;
+
+protected:
+ virtual void Scroll(int amount);
+ void SetCursor(int cursor);
+ virtual bool MoveDown(bool wrapAround);
+ virtual bool MoveUp(bool wrapAround);
+ virtual void ValidateOffset();
+ virtual void SelectItem(int item);
+};
+
diff --git a/guilib/GUIListGroup.cpp b/guilib/GUIListGroup.cpp
new file mode 100644
index 0000000000..1e093bc345
--- /dev/null
+++ b/guilib/GUIListGroup.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIListGroup.h"
+#include "GUIListLabel.h"
+#include "GUIMultiSelectText.h"
+#include "GUIBorderedImage.h"
+#include "GUIControlProfiler.h"
+#include "utils/log.h"
+
+CGUIListGroup::CGUIListGroup(int parentID, int controlID, float posX, float posY, float width, float height)
+: CGUIControlGroup(parentID, controlID, posX, posY, width, height)
+{
+ m_item = NULL;
+ ControlType = GUICONTROL_LISTGROUP;
+}
+
+CGUIListGroup::CGUIListGroup(const CGUIListGroup &right)
+: CGUIControlGroup(right)
+{
+ m_item = NULL;
+ ControlType = GUICONTROL_LISTGROUP;
+}
+
+CGUIListGroup::~CGUIListGroup(void)
+{
+ FreeResources();
+}
+
+void CGUIListGroup::AddControl(CGUIControl *control, int position /*= -1*/)
+{
+ if (control)
+ {
+ if (!(control->GetControlType() == CGUIControl::GUICONTROL_LISTLABEL ||
+ control->GetControlType() == CGUIControl::GUICONTROL_LISTGROUP ||
+ control->GetControlType() == CGUIControl::GUICONTROL_IMAGE ||
+ control->GetControlType() == CGUIControl::GUICONTROL_BORDEREDIMAGE ||
+ control->GetControlType() == CGUIControl::GUICONTROL_MULTISELECT ||
+ control->GetControlType() == CGUIControl::GUICONTROL_TEXTBOX))
+ CLog::Log(LOGWARNING, "Trying to add unsupported control type %d", control->GetControlType());
+ control->SetPushUpdates(true);
+ }
+ CGUIControlGroup::AddControl(control, position);
+}
+
+void CGUIListGroup::Render()
+{
+ g_graphicsContext.SetOrigin(m_posX, m_posY);
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *control = *it;
+ GUIPROFILER_VISIBILITY_BEGIN(control);
+ control->UpdateVisibility(m_item);
+ GUIPROFILER_VISIBILITY_END(control);
+ control->DoRender(m_renderTime);
+ }
+ CGUIControl::Render();
+ g_graphicsContext.RestoreOrigin();
+ m_item = NULL;
+}
+
+void CGUIListGroup::ResetAnimation(ANIMATION_TYPE type)
+{
+ CGUIControl::ResetAnimation(type);
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ (*it)->ResetAnimation(type);
+}
+
+void CGUIListGroup::UpdateVisibility(const CGUIListItem *item)
+{
+ CGUIControlGroup::UpdateVisibility(item);
+ m_item = item;
+}
+
+void CGUIListGroup::UpdateInfo(const CGUIListItem *item)
+{
+ for (iControls it = m_children.begin(); it != m_children.end(); it++)
+ (*it)->UpdateInfo(item);
+ // now we have to check our overlapping label pairs
+ for (unsigned int i = 0; i < m_children.size(); i++)
+ {
+ if (m_children[i]->GetControlType() == CGUIControl::GUICONTROL_LISTLABEL && m_children[i]->IsVisible())
+ {
+ CGUIListLabel &label1 = *(CGUIListLabel *)m_children[i];
+ CRect rect1(label1.GetRenderRect());
+ for (unsigned int j = i + 1; j < m_children.size(); j++)
+ {
+ if (m_children[j]->GetControlType() == CGUIControl::GUICONTROL_LISTLABEL && m_children[j]->IsVisible())
+ { // ok, now check if they overlap
+ CGUIListLabel &label2 = *(CGUIListLabel *)m_children[j];
+ if (!rect1.Intersect(label2.GetRenderRect()).IsEmpty())
+ { // overlap vertically and horizontally - check alignment
+ CGUIListLabel &left = label1.GetRenderRect().x1 < label2.GetRenderRect().x1 ? label1 : label2;
+ CGUIListLabel &right = label1.GetRenderRect().x1 < label2.GetRenderRect().x1 ? label2 : label1;
+ if ((left.GetLabelInfo().align & 3) == 0 && right.GetLabelInfo().align & XBFONT_RIGHT)
+ {
+ float chopPoint = (left.GetXPosition() + left.GetWidth() + right.GetXPosition() - right.GetWidth()) * 0.5f;
+// [1 [2...[2 1].|..........1] 2]
+// [1 [2.....[2 | 1]..1] 2]
+// [1 [2..........|.[2 1]..1] 2]
+ CRect leftRect(left.GetRenderRect());
+ CRect rightRect(right.GetRenderRect());
+ if (rightRect.x1 > chopPoint)
+ chopPoint = rightRect.x1 - 5;
+ else if (leftRect.x2 < chopPoint)
+ chopPoint = leftRect.x2 + 5;
+ leftRect.x2 = chopPoint - 5;
+ rightRect.x1 = chopPoint + 5;
+ left.SetRenderRect(leftRect);
+ right.SetRenderRect(rightRect);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void CGUIListGroup::SetFocusedItem(unsigned int focus)
+{
+ for (iControls it = m_children.begin(); it != m_children.end(); it++)
+ {
+ if ((*it)->GetControlType() == CGUIControl::GUICONTROL_MULTISELECT)
+ ((CGUIMultiSelectTextControl *)(*it))->SetFocusedItem(focus);
+ else if ((*it)->GetControlType() == CGUIControl::GUICONTROL_LISTGROUP)
+ ((CGUIListGroup *)(*it))->SetFocusedItem(focus);
+ else
+ (*it)->SetFocus(focus > 0);
+ }
+}
+
+unsigned int CGUIListGroup::GetFocusedItem() const
+{
+ for (ciControls it = m_children.begin(); it != m_children.end(); it++)
+ {
+ if ((*it)->GetControlType() == CGUIControl::GUICONTROL_MULTISELECT && ((CGUIMultiSelectTextControl *)(*it))->GetFocusedItem())
+ return ((CGUIMultiSelectTextControl *)(*it))->GetFocusedItem();
+ else if ((*it)->GetControlType() == CGUIControl::GUICONTROL_LISTGROUP && ((CGUIListGroup *)(*it))->GetFocusedItem())
+ return ((CGUIListGroup *)(*it))->GetFocusedItem();
+ }
+ return 0;
+}
+
+bool CGUIListGroup::MoveLeft()
+{
+ for (iControls it = m_children.begin(); it != m_children.end(); it++)
+ {
+ if ((*it)->GetControlType() == CGUIControl::GUICONTROL_MULTISELECT && ((CGUIMultiSelectTextControl *)(*it))->MoveLeft())
+ return true;
+ else if ((*it)->GetControlType() == CGUIControl::GUICONTROL_LISTGROUP && ((CGUIListGroup *)(*it))->MoveLeft())
+ return true;
+ }
+ return false;
+}
+
+bool CGUIListGroup::MoveRight()
+{
+ for (iControls it = m_children.begin(); it != m_children.end(); it++)
+ {
+ if ((*it)->GetControlType() == CGUIControl::GUICONTROL_MULTISELECT && ((CGUIMultiSelectTextControl *)(*it))->MoveLeft())
+ return true;
+ else if ((*it)->GetControlType() == CGUIControl::GUICONTROL_LISTGROUP && ((CGUIListGroup *)(*it))->MoveLeft())
+ return true;
+ }
+ return false;
+}
+
+void CGUIListGroup::SetState(bool selected, bool focused)
+{
+ for (iControls it = m_children.begin(); it != m_children.end(); it++)
+ {
+ if ((*it)->GetControlType() == CGUIControl::GUICONTROL_LISTLABEL)
+ {
+ CGUIListLabel *label = (CGUIListLabel *)(*it);
+ label->SetSelected(selected);
+ label->SetScrolling(focused);
+ }
+ }
+}
+
+void CGUIListGroup::SelectItemFromPoint(const CPoint &point)
+{
+ CPoint controlCoords(point);
+ m_transform.InverseTransformPosition(controlCoords.x, controlCoords.y);
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *child = *it;
+ if (child->GetControlType() == CGUIControl::GUICONTROL_MULTISELECT)
+ ((CGUIMultiSelectTextControl *)child)->SelectItemFromPoint(point);
+ else if (child->GetControlType() == CGUIControl::GUICONTROL_LISTGROUP)
+ ((CGUIListGroup *)child)->SelectItemFromPoint(point);
+ }
+}
diff --git a/guilib/GUIListGroup.h b/guilib/GUIListGroup.h
new file mode 100644
index 0000000000..241ca229f4
--- /dev/null
+++ b/guilib/GUIListGroup.h
@@ -0,0 +1,60 @@
+/*!
+\file GUIListGroup.h
+\brief
+*/
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControlGroup.h"
+
+/*!
+ \ingroup controls
+ \brief a group of controls within a list/panel container
+ */
+class CGUIListGroup : public CGUIControlGroup
+{
+public:
+ CGUIListGroup(int parentID, int controlID, float posX, float posY, float width, float height);
+ CGUIListGroup(const CGUIListGroup &right);
+ virtual ~CGUIListGroup(void);
+ virtual CGUIListGroup *Clone() const { return new CGUIListGroup(*this); };
+
+ virtual void AddControl(CGUIControl *control, int position = -1);
+
+ virtual void Render();
+ virtual void ResetAnimation(ANIMATION_TYPE type);
+ virtual void UpdateVisibility(const CGUIListItem *item = NULL);
+ virtual void UpdateInfo(const CGUIListItem *item);
+
+ void SetFocusedItem(unsigned int subfocus);
+ unsigned int GetFocusedItem() const;
+ bool MoveLeft();
+ bool MoveRight();
+ void SetState(bool selected, bool focused);
+ void SelectItemFromPoint(const CPoint &point);
+
+protected:
+ const CGUIListItem *m_item;
+};
+
diff --git a/guilib/GUIListItem.cpp b/guilib/GUIListItem.cpp
new file mode 100644
index 0000000000..9aabebfe69
--- /dev/null
+++ b/guilib/GUIListItem.cpp
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIListItem.h"
+#include "GUIListItemLayout.h"
+#include "utils/Archive.h"
+
+CGUIListItem::CGUIListItem(const CGUIListItem& item)
+{
+ *this = item;
+ SetInvalid();
+}
+
+CGUIListItem::CGUIListItem(void)
+{
+ m_bIsFolder = false;
+ m_strLabel2 = "";
+ m_strLabel = "";
+ m_bSelected = false;
+ m_strIcon = "";
+ m_strThumbnailImage = "";
+ m_overlayIcon = ICON_OVERLAY_NONE;
+ m_layout = NULL;
+ m_focusedLayout = NULL;
+}
+
+CGUIListItem::CGUIListItem(const CStdString& strLabel)
+{
+ m_bIsFolder = false;
+ m_strLabel2 = "";
+ m_strLabel = strLabel;
+ m_sortLabel = strLabel;
+ m_bSelected = false;
+ m_strIcon = "";
+ m_strThumbnailImage = "";
+ m_overlayIcon = ICON_OVERLAY_NONE;
+ m_layout = NULL;
+ m_focusedLayout = NULL;
+}
+
+CGUIListItem::~CGUIListItem(void)
+{
+ FreeMemory();
+}
+
+void CGUIListItem::SetLabel(const CStdString& strLabel)
+{
+ m_strLabel = strLabel;
+ if (m_sortLabel.IsEmpty())
+ m_sortLabel = strLabel;
+ SetInvalid();
+}
+
+const CStdString& CGUIListItem::GetLabel() const
+{
+ return m_strLabel;
+}
+
+
+void CGUIListItem::SetLabel2(const CStdString& strLabel2)
+{
+ m_strLabel2 = strLabel2;
+ SetInvalid();
+}
+
+const CStdString& CGUIListItem::GetLabel2() const
+{
+ return m_strLabel2;
+}
+
+void CGUIListItem::SetSortLabel(const CStdString &label)
+{
+ m_sortLabel = label;
+ // no need to invalidate - this is never shown in the UI
+}
+
+const CStdString& CGUIListItem::GetSortLabel() const
+{
+ return m_sortLabel;
+}
+
+void CGUIListItem::SetThumbnailImage(const CStdString& strThumbnail)
+{
+ m_strThumbnailImage = strThumbnail;
+ SetInvalid();
+}
+
+const CStdString& CGUIListItem::GetThumbnailImage() const
+{
+ return m_strThumbnailImage;
+}
+
+void CGUIListItem::SetIconImage(const CStdString& strIcon)
+{
+ m_strIcon = strIcon;
+ SetInvalid();
+}
+
+const CStdString& CGUIListItem::GetIconImage() const
+{
+ return m_strIcon;
+}
+
+void CGUIListItem::SetOverlayImage(GUIIconOverlay icon, bool bOnOff)
+{
+ if (bOnOff)
+ m_overlayIcon = GUIIconOverlay((int)(icon)+1);
+ else
+ m_overlayIcon = icon;
+ SetInvalid();
+}
+
+CStdString CGUIListItem::GetOverlayImage() const
+{
+ switch (m_overlayIcon)
+ {
+ case ICON_OVERLAY_RAR:
+ return "OverlayRAR.png";
+ case ICON_OVERLAY_ZIP:
+ return "OverlayZIP.png";
+ case ICON_OVERLAY_TRAINED:
+ return "OverlayTrained.png";
+ case ICON_OVERLAY_HAS_TRAINER:
+ return "OverlayHasTrainer.png";
+ case ICON_OVERLAY_LOCKED:
+ return "OverlayLocked.png";
+ case ICON_OVERLAY_UNWATCHED:
+ return "OverlayUnwatched.png";
+ case ICON_OVERLAY_WATCHED:
+ return "OverlayWatched.png";
+ case ICON_OVERLAY_HD:
+ return "OverlayHD.png";
+ default:
+ return "";
+ }
+}
+
+void CGUIListItem::Select(bool bOnOff)
+{
+ m_bSelected = bOnOff;
+}
+
+bool CGUIListItem::HasIcon() const
+{
+ return (m_strIcon.size() != 0);
+}
+
+
+bool CGUIListItem::HasThumbnail() const
+{
+ return (m_strThumbnailImage.size() != 0);
+}
+
+bool CGUIListItem::HasOverlay() const
+{
+ return (m_overlayIcon != CGUIListItem::ICON_OVERLAY_NONE);
+}
+
+bool CGUIListItem::IsSelected() const
+{
+ return m_bSelected;
+}
+
+const CGUIListItem& CGUIListItem::operator =(const CGUIListItem& item)
+{
+ if (&item == this) return * this;
+ m_strLabel2 = item.m_strLabel2;
+ m_strLabel = item.m_strLabel;
+ m_sortLabel = item.m_sortLabel;
+ FreeMemory();
+ m_bSelected = item.m_bSelected;
+ m_strIcon = item.m_strIcon;
+ m_strThumbnailImage = item.m_strThumbnailImage;
+ m_overlayIcon = item.m_overlayIcon;
+ m_bIsFolder = item.m_bIsFolder;
+ m_mapProperties = item.m_mapProperties;
+ SetInvalid();
+ return *this;
+}
+
+void CGUIListItem::Serialize(CArchive &ar)
+{
+ if (ar.IsStoring())
+ {
+ ar << m_bIsFolder;
+ ar << m_strLabel;
+ ar << m_strLabel2;
+ ar << m_sortLabel;
+ ar << m_strThumbnailImage;
+ ar << m_strIcon;
+ ar << m_bSelected;
+ ar << m_overlayIcon;
+ ar << (int)m_mapProperties.size();
+ for (std::map<CStdString, CStdString, icompare>::const_iterator it = m_mapProperties.begin(); it != m_mapProperties.end(); it++)
+ {
+ ar << it->first;
+ ar << it->second;
+ }
+ }
+ else
+ {
+ ar >> m_bIsFolder;
+ ar >> m_strLabel;
+ ar >> m_strLabel2;
+ ar >> m_sortLabel;
+ ar >> m_strThumbnailImage;
+ ar >> m_strIcon;
+ ar >> m_bSelected;
+
+ int overlayIcon;
+ ar >> overlayIcon;
+ m_overlayIcon = GUIIconOverlay(overlayIcon);
+
+ int mapSize;
+ ar >> mapSize;
+ for (int i = 0; i < mapSize; i++)
+ {
+ CStdString key, value;
+ ar >> key;
+ ar >> value;
+ SetProperty(key, value);
+ }
+ }
+}
+
+void CGUIListItem::FreeIcons()
+{
+ FreeMemory();
+ m_strThumbnailImage = "";
+ m_strIcon = "";
+ SetInvalid();
+}
+
+void CGUIListItem::FreeMemory()
+{
+ if (m_layout)
+ {
+ delete m_layout;
+ m_layout = NULL;
+ }
+ if (m_focusedLayout)
+ {
+ delete m_focusedLayout;
+ m_focusedLayout = NULL;
+ }
+}
+
+void CGUIListItem::SetLayout(CGUIListItemLayout *layout)
+{
+ delete m_layout;
+ m_layout = layout;
+}
+
+CGUIListItemLayout *CGUIListItem::GetLayout()
+{
+ return m_layout;
+}
+
+void CGUIListItem::SetFocusedLayout(CGUIListItemLayout *layout)
+{
+ delete m_focusedLayout;
+ m_focusedLayout = layout;
+}
+
+CGUIListItemLayout *CGUIListItem::GetFocusedLayout()
+{
+ return m_focusedLayout;
+}
+
+void CGUIListItem::SetInvalid()
+{
+ if (m_layout) m_layout->SetInvalid();
+ if (m_focusedLayout) m_focusedLayout->SetInvalid();
+}
+
+void CGUIListItem::SetProperty(const CStdString &strKey, const char *strValue)
+{
+ m_mapProperties[strKey] = strValue;
+}
+
+void CGUIListItem::SetProperty(const CStdString &strKey, const CStdString &strValue)
+{
+ m_mapProperties[strKey] = strValue;
+}
+
+CStdString CGUIListItem::GetProperty(const CStdString &strKey) const
+{
+ std::map<CStdString,CStdString,icompare>::const_iterator iter = m_mapProperties.find(strKey);
+ if (iter == m_mapProperties.end())
+ return "";
+
+ return iter->second;
+}
+
+bool CGUIListItem::HasProperty(const CStdString &strKey) const
+{
+ std::map<CStdString,CStdString,icompare>::const_iterator iter = m_mapProperties.find(strKey);
+ if (iter == m_mapProperties.end())
+ return false;
+
+ return true;
+}
+
+void CGUIListItem::ClearProperty(const CStdString &strKey)
+{
+ std::map<CStdString,CStdString,icompare>::iterator iter = m_mapProperties.find(strKey);
+ if (iter != m_mapProperties.end())
+ m_mapProperties.erase(iter);
+}
+
+void CGUIListItem::ClearProperties()
+{
+ m_mapProperties.clear();
+}
+
+void CGUIListItem::SetProperty(const CStdString &strKey, int nVal)
+{
+ CStdString strVal;
+ strVal.Format("%d",nVal);
+ SetProperty(strKey, strVal);
+}
+
+void CGUIListItem::IncrementProperty(const CStdString &strKey, int nVal)
+{
+ int i = GetPropertyInt(strKey);
+ i += nVal;
+ SetProperty(strKey, i);
+}
+
+void CGUIListItem::SetProperty(const CStdString &strKey, bool bVal)
+{
+ SetProperty(strKey, bVal?"1":"0");
+}
+
+void CGUIListItem::SetProperty(const CStdString &strKey, double dVal)
+{
+ CStdString strVal;
+ strVal.Format("%f",dVal);
+ SetProperty(strKey, strVal);
+}
+
+void CGUIListItem::IncrementProperty(const CStdString &strKey, double dVal)
+{
+ double d = GetPropertyDouble(strKey);
+ d += dVal;
+ SetProperty(strKey, d);
+}
+
+bool CGUIListItem::GetPropertyBOOL(const CStdString &strKey) const
+{
+ return GetProperty(strKey) == "1";
+}
+
+int CGUIListItem::GetPropertyInt(const CStdString &strKey) const
+{
+ return atoi(GetProperty(strKey).c_str()) ;
+}
+
+double CGUIListItem::GetPropertyDouble(const CStdString &strKey) const
+{
+ return atof(GetProperty(strKey).c_str()) ;
+}
+
+
diff --git a/guilib/GUIListItem.h b/guilib/GUIListItem.h
new file mode 100644
index 0000000000..7384410812
--- /dev/null
+++ b/guilib/GUIListItem.h
@@ -0,0 +1,150 @@
+/*!
+\file GUIListItem.h
+\brief
+*/
+
+#ifndef GUILIB_GUILISTITEM_H
+#define GUILIB_GUILISTITEM_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "StdString.h"
+
+#include <map>
+#include <string>
+
+// Forward
+class CGUIListItemLayout;
+class CArchive;
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIListItem
+{
+public:
+ enum GUIIconOverlay { ICON_OVERLAY_NONE = 0,
+ ICON_OVERLAY_RAR,
+ ICON_OVERLAY_ZIP,
+ ICON_OVERLAY_LOCKED,
+ ICON_OVERLAY_HAS_TRAINER,
+ ICON_OVERLAY_TRAINED,
+ ICON_OVERLAY_UNWATCHED,
+ ICON_OVERLAY_WATCHED,
+ ICON_OVERLAY_HD};
+
+ CGUIListItem(void);
+ CGUIListItem(const CGUIListItem& item);
+ CGUIListItem(const CStdString& strLabel);
+ virtual ~CGUIListItem(void);
+
+
+ const CGUIListItem& operator =(const CGUIListItem& item);
+
+ virtual void SetLabel(const CStdString& strLabel);
+ const CStdString& GetLabel() const;
+
+ void SetLabel2(const CStdString& strLabel);
+ const CStdString& GetLabel2() const;
+
+ void SetIconImage(const CStdString& strIcon);
+ const CStdString& GetIconImage() const;
+
+ void SetThumbnailImage(const CStdString& strThumbnail);
+ const CStdString& GetThumbnailImage() const;
+
+ void SetOverlayImage(GUIIconOverlay icon, bool bOnOff=false);
+ CStdString GetOverlayImage() const;
+
+ void SetSortLabel(const CStdString &label);
+ const CStdString &GetSortLabel() const;
+
+ void Select(bool bOnOff);
+ bool IsSelected() const;
+
+ bool HasIcon() const;
+ bool HasThumbnail() const;
+ bool HasOverlay() const;
+ virtual bool IsFileItem() const { return false; };
+
+ void SetLayout(CGUIListItemLayout *layout);
+ CGUIListItemLayout *GetLayout();
+
+ void SetFocusedLayout(CGUIListItemLayout *layout);
+ CGUIListItemLayout *GetFocusedLayout();
+
+ void FreeIcons();
+ void FreeMemory();
+ void SetInvalid();
+
+ bool m_bIsFolder; ///< is item a folder or a file
+
+ void SetProperty(const CStdString &strKey, const char *strValue);
+ void SetProperty(const CStdString &strKey, const CStdString &strValue);
+ void SetProperty(const CStdString &strKey, int nVal);
+ void SetProperty(const CStdString &strKey, bool bVal);
+ void SetProperty(const CStdString &strKey, double dVal);
+
+ void IncrementProperty(const CStdString &strKey, int nVal);
+ void IncrementProperty(const CStdString &strKey, double dVal);
+
+ void ClearProperties();
+
+ void Serialize(CArchive& ar);
+
+ bool HasProperty(const CStdString &strKey) const;
+ bool HasProperties() const { return m_mapProperties.size() > 0; };
+ void ClearProperty(const CStdString &strKey);
+
+ CStdString GetProperty(const CStdString &strKey) const;
+ bool GetPropertyBOOL(const CStdString &strKey) const;
+ int GetPropertyInt(const CStdString &strKey) const;
+ double GetPropertyDouble(const CStdString &strKey) const;
+
+protected:
+ CStdString m_strLabel2; // text of column2
+ CStdString m_strThumbnailImage; // filename of thumbnail
+ CStdString m_strIcon; // filename of icon
+ GUIIconOverlay m_overlayIcon; // type of overlay icon
+
+ CGUIListItemLayout *m_layout;
+ CGUIListItemLayout *m_focusedLayout;
+ bool m_bSelected; // item is selected or not
+
+ struct icompare
+ {
+ bool operator()(const CStdString &s1, const CStdString &s2) const
+ {
+ return s1.CompareNoCase(s2) < 0;
+ }
+ };
+
+ std::map<CStdString, CStdString, icompare> m_mapProperties;
+private:
+ CStdString m_sortLabel; // text for sorting
+ CStdString m_strLabel; // text of column1
+};
+#endif
+
diff --git a/guilib/GUIListItemLayout.cpp b/guilib/GUIListItemLayout.cpp
new file mode 100644
index 0000000000..7f5eae3da4
--- /dev/null
+++ b/guilib/GUIListItemLayout.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIListItemLayout.h"
+#include "FileItem.h"
+#include "GUIControlFactory.h"
+#include "SkinInfo.h"
+#include "utils/GUIInfoManager.h"
+#include "GUIListLabel.h"
+#include "GUIImage.h"
+#include "tinyXML/tinyxml.h"
+
+using namespace std;
+
+CGUIListItemLayout::CGUIListItemLayout()
+: m_group(0, 0, 0, 0, 0, 0)
+{
+ m_width = 0;
+ m_height = 0;
+ m_condition = 0;
+ m_focused = false;
+ m_invalidated = true;
+ m_isPlaying = false;
+}
+
+CGUIListItemLayout::CGUIListItemLayout(const CGUIListItemLayout &from)
+: m_group(from.m_group)
+{
+ m_width = from.m_width;
+ m_height = from.m_height;
+ m_focused = from.m_focused;
+ m_condition = from.m_condition;
+ m_invalidated = true;
+ m_isPlaying = false;
+}
+
+CGUIListItemLayout::~CGUIListItemLayout()
+{
+}
+
+bool CGUIListItemLayout::IsAnimating(ANIMATION_TYPE animType)
+{
+ return m_group.IsAnimating(animType);
+}
+
+void CGUIListItemLayout::ResetAnimation(ANIMATION_TYPE animType)
+{
+ return m_group.ResetAnimation(animType);
+}
+
+float CGUIListItemLayout::Size(ORIENTATION orientation) const
+{
+ return (orientation == HORIZONTAL) ? m_width : m_height;
+}
+
+void CGUIListItemLayout::Render(CGUIListItem *item, int parentID, DWORD time)
+{
+ if (m_invalidated)
+ { // need to update our item
+ // could use a dynamic cast here if RTTI was enabled. As it's not,
+ // let's use a static cast with a virtual base function
+ CFileItem *fileItem = item->IsFileItem() ? (CFileItem *)item : new CFileItem(*item);
+ m_isPlaying = g_infoManager.GetBool(LISTITEM_ISPLAYING, parentID, item);
+ m_group.SetInvalid();
+ m_group.UpdateInfo(fileItem);
+ m_invalidated = false;
+ // delete our temporary fileitem
+ if (!item->IsFileItem())
+ delete fileItem;
+ }
+
+ // update visibility, and render
+ m_group.SetState(item->IsSelected() || m_isPlaying, m_focused);
+ m_group.UpdateVisibility(item);
+ m_group.DoRender(time);
+}
+
+void CGUIListItemLayout::SetFocusedItem(unsigned int focus)
+{
+ m_group.SetFocusedItem(focus);
+}
+
+unsigned int CGUIListItemLayout::GetFocusedItem() const
+{
+ return m_group.GetFocusedItem();
+}
+
+void CGUIListItemLayout::SelectItemFromPoint(const CPoint &point)
+{
+ m_group.SelectItemFromPoint(point);
+}
+
+bool CGUIListItemLayout::MoveLeft()
+{
+ return m_group.MoveLeft();
+}
+
+bool CGUIListItemLayout::MoveRight()
+{
+ return m_group.MoveRight();
+}
+
+void CGUIListItemLayout::LoadControl(TiXmlElement *child, CGUIControlGroup *group)
+{
+ if (!group) return;
+
+ FRECT rect = { group->GetXPosition(), group->GetYPosition(), group->GetXPosition() + group->GetWidth(), group->GetYPosition() + group->GetHeight() };
+
+ CGUIControlFactory factory;
+ CGUIControl *control = factory.Create(0, rect, child, true); // true indicating we're inside a list for the
+ // different label control + defaults.
+ if (control)
+ {
+ group->AddControl(control);
+ if (control->IsGroup())
+ {
+ TiXmlElement *grandChild = child->FirstChildElement("control");
+ while (grandChild)
+ {
+ LoadControl(grandChild, (CGUIControlGroup *)control);
+ grandChild = grandChild->NextSiblingElement("control");
+ }
+ }
+ }
+}
+
+void CGUIListItemLayout::LoadLayout(TiXmlElement *layout, bool focused)
+{
+ m_focused = focused;
+ g_SkinInfo.ResolveIncludes(layout);
+ g_SkinInfo.ResolveConstant(layout->Attribute("width"), m_width);
+ g_SkinInfo.ResolveConstant(layout->Attribute("height"), m_height);
+ const char *condition = layout->Attribute("condition");
+ if (condition)
+ m_condition = g_infoManager.TranslateString(condition);
+ TiXmlElement *child = layout->FirstChildElement("control");
+ m_group.SetWidth(m_width);
+ m_group.SetHeight(m_height);
+ while (child)
+ {
+ LoadControl(child, &m_group);
+ child = child->NextSiblingElement("control");
+ }
+}
+
+//#ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY
+void CGUIListItemLayout::CreateListControlLayouts(float width, float height, bool focused, const CLabelInfo &labelInfo, const CLabelInfo &labelInfo2, const CTextureInfo &texture, const CTextureInfo &textureFocus, float texHeight, float iconWidth, float iconHeight, int nofocusCondition, int focusCondition)
+{
+ m_width = width;
+ m_height = height;
+ m_focused = focused;
+ CGUIImage *tex = new CGUIImage(0, 0, 0, 0, width, texHeight, texture);
+ tex->SetVisibleCondition(nofocusCondition, false);
+ m_group.AddControl(tex);
+ if (focused)
+ {
+ CGUIImage *tex = new CGUIImage(0, 0, 0, 0, width, texHeight, textureFocus);
+ tex->SetVisibleCondition(focusCondition, false);
+ m_group.AddControl(tex);
+ }
+ CGUIImage *image = new CGUIImage(0, 0, 8, 0, iconWidth, texHeight, CTextureInfo(""));
+ image->SetInfo(CGUIInfoLabel("$INFO[ListItem.Icon]"));
+ image->SetAspectRatio(CAspectRatio::AR_KEEP);
+ m_group.AddControl(image);
+ float x = iconWidth + labelInfo.offsetX + 10;
+ CGUIListLabel *label = new CGUIListLabel(0, 0, x, labelInfo.offsetY, width - x - 18, height, labelInfo, CGUIInfoLabel("$INFO[ListItem.Label]"), false, CScrollInfo::defaultSpeed);
+ m_group.AddControl(label);
+ x = labelInfo2.offsetX ? labelInfo2.offsetX : m_width - 16;
+ label = new CGUIListLabel(0, 0, x, labelInfo2.offsetY, x - iconWidth - 20, height, labelInfo2, CGUIInfoLabel("$INFO[ListItem.Label2]"), false, CScrollInfo::defaultSpeed);
+ m_group.AddControl(label);
+}
+//#endif
+
+#ifdef _DEBUG
+void CGUIListItemLayout::DumpTextureUse()
+{
+ m_group.DumpTextureUse();
+}
+#endif
diff --git a/guilib/GUIListItemLayout.h b/guilib/GUIListItemLayout.h
new file mode 100644
index 0000000000..f0c03ba641
--- /dev/null
+++ b/guilib/GUIListItemLayout.h
@@ -0,0 +1,71 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIListGroup.h"
+#include "GUITexture.h"
+
+class CGUIListItem;
+class CFileItem;
+
+class CGUIListItemLayout
+{
+public:
+ CGUIListItemLayout();
+ CGUIListItemLayout(const CGUIListItemLayout &from);
+ virtual ~CGUIListItemLayout();
+ void LoadLayout(TiXmlElement *layout, bool focused);
+ void Render(CGUIListItem *item, int parentID, DWORD time = 0);
+ float Size(ORIENTATION orientation) const;
+ unsigned int GetFocusedItem() const;
+ void SetFocusedItem(unsigned int focus);
+ bool IsAnimating(ANIMATION_TYPE animType);
+ void ResetAnimation(ANIMATION_TYPE animType);
+ void SetInvalid() { m_invalidated = true; };
+
+//#ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY
+ void CreateListControlLayouts(float width, float height, bool focused, const CLabelInfo &labelInfo, const CLabelInfo &labelInfo2, const CTextureInfo &texture, const CTextureInfo &textureFocus, float texHeight, float iconWidth, float iconHeight, int nofocusCondition, int focusCondition);
+//#endif
+
+ void SelectItemFromPoint(const CPoint &point);
+ bool MoveLeft();
+ bool MoveRight();
+
+ int GetCondition() const { return m_condition; };
+#ifdef _DEBUG
+ virtual void DumpTextureUse();
+#endif
+protected:
+ void LoadControl(TiXmlElement *child, CGUIControlGroup *group);
+ void Update(CFileItem *item);
+
+ CGUIListGroup m_group;
+
+ float m_width;
+ float m_height;
+ bool m_focused;
+ bool m_invalidated;
+
+ int m_condition;
+ bool m_isPlaying;
+};
+
diff --git a/guilib/GUIListLabel.cpp b/guilib/GUIListLabel.cpp
new file mode 100644
index 0000000000..b08d473549
--- /dev/null
+++ b/guilib/GUIListLabel.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIListLabel.h"
+#include "utils/CharsetConverter.h"
+#include <limits>
+
+CGUIListLabel::CGUIListLabel(int parentID, int controlID, float posX, float posY, float width, float height, const CLabelInfo& labelInfo, const CGUIInfoLabel &info, bool alwaysScroll, int scrollSpeed)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+ , m_textLayout(labelInfo.font, false)
+ , m_scrollInfo(50, 0, scrollSpeed)
+ , m_renderRect()
+{
+ m_selected = false;
+ m_scrolling = m_alwaysScroll = alwaysScroll;
+ m_label = labelInfo;
+ m_info = info;
+ m_textWidth = width;
+ if (m_info.IsConstant())
+ SetLabel(m_info.GetLabel(m_parentID, true));
+ ControlType = GUICONTROL_LISTLABEL;
+}
+
+CGUIListLabel::~CGUIListLabel(void)
+{
+}
+
+void CGUIListLabel::SetScrolling(bool scrolling)
+{
+ m_scrolling = m_alwaysScroll ? true : scrolling;
+ if (!m_scrolling)
+ m_scrollInfo.Reset();
+}
+
+void CGUIListLabel::SetSelected(bool selected)
+{
+ m_selected = selected;
+}
+
+void CGUIListLabel::SetFocus(bool focus)
+{
+ CGUIControl::SetFocus(focus);
+ if (!focus)
+ SetScrolling(false);
+}
+
+void CGUIListLabel::UpdateColors()
+{
+ m_label.UpdateColors();
+ CGUIControl::UpdateColors();
+}
+
+void CGUIListLabel::Render()
+{
+ color_t color = m_selected ? m_label.selectedColor : m_label.textColor;
+ bool needsToScroll = (m_renderRect.Width() + 0.5f < m_textWidth); // 0.5f to deal with floating point rounding issues
+ if (m_scrolling && needsToScroll)
+ m_textLayout.RenderScrolling(m_renderRect.x1, m_renderRect.y1, m_label.angle, color, m_label.shadowColor, 0, m_renderRect.Width(), m_scrollInfo);
+ else
+ {
+ float posX = m_renderRect.x1;
+ uint32_t align = 0;
+ if (!needsToScroll)
+ { // hack for right and centered multiline text, as GUITextLayout::Render() treats posX as the right hand
+ // or center edge of the text (see GUIFontTTF::DrawTextInternal), and this has already been taken care of
+ // in SetLabel(), but we wish to still pass the horizontal alignment info through (so that multiline text
+ // is aligned correctly), so we must undo the SetLabel() changes for horizontal alignment.
+ if (m_label.align & XBFONT_RIGHT)
+ posX += m_renderRect.Width();
+ else if (m_label.align & XBFONT_CENTER_X)
+ posX += m_renderRect.Width() * 0.5f;
+ align = m_label.align & ~XBFONT_CENTER_Y; // ignore vertical alignment
+ }
+ m_textLayout.Render(posX, m_renderRect.y1, m_label.angle, color, m_label.shadowColor, align, m_renderRect.Width());
+ }
+ CGUIControl::Render();
+}
+
+void CGUIListLabel::UpdateInfo(const CGUIListItem *item)
+{
+ if (m_info.IsConstant() && !m_bInvalidated)
+ return; // nothing to do
+
+ if (item)
+ SetLabel(m_info.GetItemLabel(item));
+ else
+ SetLabel(m_info.GetLabel(m_parentID, true));
+}
+
+void CGUIListLabel::SetLabel(const CStdString &label)
+{
+ if (m_textLayout.Update(label, 0, m_bInvalidated))
+ { // needed an update - reset scrolling
+ m_scrollInfo.Reset();
+ // recalculate our text layout
+ float width, height;
+ m_textLayout.GetTextExtent(m_textWidth, height);
+ width = std::min(m_textWidth, m_width);
+ if (m_label.align & XBFONT_CENTER_Y)
+ m_renderRect.y1 = m_posY + (m_height - height) * 0.5f;
+ else
+ m_renderRect.y1 = m_posY;
+ if (m_label.align & XBFONT_RIGHT)
+ m_renderRect.x1 = m_posX - width;
+ else if (m_label.align & XBFONT_CENTER_X)
+ m_renderRect.x1 = m_posX - width * 0.5f;
+ else
+ m_renderRect.x1 = m_posX;
+ m_renderRect.x2 = m_renderRect.x1 + width;
+ m_renderRect.y2 = m_renderRect.y1 + height;
+ }
+}
diff --git a/guilib/GUIListLabel.h b/guilib/GUIListLabel.h
new file mode 100644
index 0000000000..9ef10c6e79
--- /dev/null
+++ b/guilib/GUIListLabel.h
@@ -0,0 +1,70 @@
+/*!
+\file GUIListLabel.h
+\brief
+*/
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+
+#include "GUILabelControl.h" // for CLabelInfo
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIListLabel :
+ public CGUIControl
+{
+public:
+ CGUIListLabel(int parentID, int controlID, float posX, float posY, float width, float height, const CLabelInfo& labelInfo, const CGUIInfoLabel &label, bool alwaysScroll, int scrollSpeed);
+ virtual ~CGUIListLabel(void);
+ virtual CGUIListLabel *Clone() const { return new CGUIListLabel(*this); };
+
+ virtual void Render();
+ virtual bool CanFocus() const { return false; };
+ virtual void UpdateInfo(const CGUIListItem *item = NULL);
+ virtual void SetFocus(bool focus);
+
+ const CRect &GetRenderRect() const { return m_renderRect; };
+ void SetRenderRect(const CRect &rect) { m_renderRect = rect; };
+ void SetLabel(const CStdString &label);
+ void SetSelected(bool selected);
+ void SetScrolling(bool scrolling);
+
+ const CLabelInfo& GetLabelInfo() const { return m_label; };
+
+protected:
+ virtual void UpdateColors();
+
+ CLabelInfo m_label;
+ CGUITextLayout m_textLayout;
+ CGUIInfoLabel m_info;
+ float m_textWidth;
+
+ bool m_scrolling;
+ bool m_alwaysScroll;
+ bool m_selected;
+ CScrollInfo m_scrollInfo;
+ CRect m_renderRect; // render location
+};
diff --git a/guilib/GUIMessage.cpp b/guilib/GUIMessage.cpp
new file mode 100644
index 0000000000..6a08bd36b5
--- /dev/null
+++ b/guilib/GUIMessage.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIMessage.h"
+#include "LocalizeStrings.h"
+
+using namespace std;
+
+CStdString CGUIMessage::empty_string;
+
+CGUIMessage::CGUIMessage(int msg, int senderID, int controlID, int param1, int param2)
+{
+ m_message = msg;
+ m_senderID = senderID;
+ m_controlID = controlID;
+ m_param1 = param1;
+ m_param2 = param2;
+ m_pointer = NULL;
+}
+
+CGUIMessage::CGUIMessage(int msg, int senderID, int controlID, int param1, int param2, CFileItemList *item)
+{
+ m_message = msg;
+ m_senderID = senderID;
+ m_controlID = controlID;
+ m_param1 = param1;
+ m_param2 = param2;
+ m_pointer = item;
+}
+
+CGUIMessage::CGUIMessage(int msg, int senderID, int controlID, int param1, int param2, const CGUIListItemPtr &item)
+{
+ m_message = msg;
+ m_senderID = senderID;
+ m_controlID = controlID;
+ m_param1 = param1;
+ m_param2 = param2;
+ m_pointer = NULL;
+ m_item = item;
+}
+
+CGUIMessage::CGUIMessage(int msg, int senderID, int controlID, int param1, int param2, CVisualisation* vis)
+{
+ m_message = msg;
+ m_senderID = senderID;
+ m_controlID = controlID;
+ m_param1 = param1;
+ m_param2 = param2;
+ m_pointer = vis;
+}
+
+CGUIMessage::CGUIMessage(const CGUIMessage& msg)
+{
+ *this = msg;
+}
+
+CGUIMessage::~CGUIMessage(void)
+{}
+
+
+int CGUIMessage::GetControlId() const
+{
+ return m_controlID;
+}
+
+int CGUIMessage::GetMessage() const
+{
+ return m_message;
+}
+
+void* CGUIMessage::GetPointer() const
+{
+ return m_pointer;
+}
+
+CGUIListItemPtr CGUIMessage::GetItem() const
+{
+ return m_item;
+}
+
+int CGUIMessage::GetParam1() const
+{
+ return m_param1;
+}
+
+int CGUIMessage::GetParam2() const
+{
+ return m_param2;
+}
+
+int CGUIMessage::GetSenderId() const
+{
+ return m_senderID;
+}
+
+
+const CGUIMessage& CGUIMessage::operator = (const CGUIMessage& msg)
+{
+ if (this == &msg) return * this;
+
+ m_message = msg.m_message;
+ m_controlID = msg.m_controlID;
+ m_param1 = msg.m_param1;
+ m_param2 = msg.m_param2;
+ m_pointer = msg.m_pointer;
+ m_strLabel = msg.m_strLabel;
+ m_senderID = msg.m_senderID;
+ m_params = msg.m_params;
+ m_item = msg.m_item;
+ m_action = msg.m_action;
+ return *this;
+}
+
+
+void CGUIMessage::SetParam1(int param1)
+{
+ m_param1 = param1;
+}
+
+void CGUIMessage::SetParam2(int param2)
+{
+ m_param2 = param2;
+}
+
+void CGUIMessage::SetPointer(void* lpVoid)
+{
+ m_pointer = lpVoid;
+}
+
+void CGUIMessage::SetLabel(const string& strLabel)
+{
+ m_strLabel = strLabel;
+}
+
+const string& CGUIMessage::GetLabel() const
+{
+ return m_strLabel;
+}
+
+void CGUIMessage::SetLabel(int iString)
+{
+ m_strLabel = g_localizeStrings.Get(iString);
+}
+
+void CGUIMessage::SetStringParam(const CStdString& strParam)
+{
+ m_params.clear();
+ if (strParam.size())
+ m_params.push_back(strParam);
+}
+
+void CGUIMessage::SetStringParams(const vector<CStdString> &params)
+{
+ m_params = params;
+}
+
+const CStdString& CGUIMessage::GetStringParam(size_t param) const
+{
+ if (param >= m_params.size())
+ return empty_string;
+ return m_params[param];
+}
+
+size_t CGUIMessage::GetNumStringParams() const
+{
+ return m_params.size();
+}
+
+void CGUIMessage::SetAction(const CGUIActionDescriptor& action)
+{
+ m_action = action;
+}
+
+const CGUIActionDescriptor& CGUIMessage::GetAction() const
+{
+ return m_action;
+}
diff --git a/guilib/GUIMessage.h b/guilib/GUIMessage.h
new file mode 100644
index 0000000000..c5cf464d00
--- /dev/null
+++ b/guilib/GUIMessage.h
@@ -0,0 +1,288 @@
+/*!
+\file GUIMessage.h
+\brief
+*/
+
+#ifndef GUILIB_MESSAGE_H
+#define GUILIB_MESSAGE_H
+
+#include "GUIActionDescriptor.h"
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#define GUI_MSG_WINDOW_INIT 1 // initialize window
+#define GUI_MSG_WINDOW_DEINIT 2 // deinit window
+#define GUI_MSG_WINDOW_RESET 27 // reset window to initial state
+
+#define GUI_MSG_SETFOCUS 3 // set focus to control param1=up/down/left/right
+#define GUI_MSG_LOSTFOCUS 4 // control lost focus
+
+#define GUI_MSG_CLICKED 5 // control has been clicked
+
+#define GUI_MSG_VISIBLE 6 // set control visible
+#define GUI_MSG_HIDDEN 7 // set control hidden
+
+#define GUI_MSG_ENABLED 8 // enable control
+#define GUI_MSG_DISABLED 9 // disable control
+
+#define GUI_MSG_SELECTED 10 // control = selected
+#define GUI_MSG_DESELECTED 11 // control = not selected
+
+#define GUI_MSG_LABEL_ADD 12 // add label control (for controls supporting more then 1 label)
+
+#define GUI_MSG_LABEL_SET 13 // set the label of a control
+
+#define GUI_MSG_LABEL_RESET 14 // clear all labels of a control // add label control (for controls supporting more then 1 label)
+
+#define GUI_MSG_ITEM_SELECTED 15 // ask control 2 return the selected item
+#define GUI_MSG_ITEM_SELECT 16 // ask control 2 select a specific item
+#define GUI_MSG_LABEL2_SET 17
+#define GUI_MSG_SHOWRANGE 18
+
+#define GUI_MSG_FULLSCREEN 19 // should go to fullscreen window (vis or video)
+#define GUI_MSG_EXECUTE 20 // user has clicked on a button with <execute> tag
+
+#define GUI_MSG_NOTIFY_ALL 21 // message will be send to all active and inactive(!) windows, all active modal and modeless dialogs
+ // dwParam1 must contain an additional message the windows should react on
+
+#define GUI_MSG_REFRESH_THUMBS 22 // message is sent to all windows to refresh all thumbs
+
+#define GUI_MSG_MOVE 23 // message is sent to the window from the base control class when it's
+ // been asked to move. dwParam1 contains direction.
+
+#define GUI_MSG_LABEL_BIND 24 // bind label control (for controls supporting more then 1 label)
+
+#define GUI_MSG_SELCHANGED 25 // selection within the control has changed
+
+#define GUI_MSG_FOCUSED 26 // a control has become focused
+
+#define GUI_MSG_PAGE_CHANGE 28 // a page control has changed the page number
+
+#define GUI_MSG_REFRESH_LIST 29 // message sent to all listing controls telling them to refresh their item layouts
+
+#define GUI_MSG_PAGE_UP 30 // page up
+#define GUI_MSG_PAGE_DOWN 31 // page down
+#define GUI_MSG_MOVE_OFFSET 32 // Instruct the contorl to MoveUp or MoveDown by offset amount
+
+#define GUI_MSG_SET_TYPE 33 ///< Instruct a control to set it's type appropriately
+
+#define GUI_MSG_INVALIDATE 34 ///< Instruct all controls to refresh - usually due to sizing changes
+
+#define GUI_MSG_USER 1000
+
+/*!
+ \ingroup winmsg
+ \brief
+ */
+#define CONTROL_SELECT(controlID) \
+do { \
+ CGUIMessage msg(GUI_MSG_SELECTED, GetID(), controlID); \
+ OnMessage(msg); \
+} while(0)
+
+/*!
+ \ingroup winmsg
+ \brief
+ */
+#define CONTROL_DESELECT(controlID) \
+do { \
+ CGUIMessage msg(GUI_MSG_DESELECTED, GetID(), controlID); \
+ OnMessage(msg); \
+} while(0)
+
+
+/*!
+ \ingroup winmsg
+ \brief
+ */
+#define CONTROL_ENABLE(controlID) \
+do { \
+ CGUIMessage msg(GUI_MSG_ENABLED, GetID(), controlID); \
+ OnMessage(msg); \
+} while(0)
+
+/*!
+ \ingroup winmsg
+ \brief
+ */
+#define CONTROL_DISABLE(controlID) \
+do { \
+ CGUIMessage msg(GUI_MSG_DISABLED, GetID(), controlID); \
+ OnMessage(msg); \
+} while(0)
+
+
+/*!
+ \ingroup winmsg
+ \brief
+ */
+#define CONTROL_ENABLE_ON_CONDITION(controlID, bCondition) \
+do { \
+ CGUIMessage msg(bCondition ? GUI_MSG_ENABLED:GUI_MSG_DISABLED, GetID(), controlID); \
+ OnMessage(msg); \
+} while(0)
+
+
+/*!
+ \ingroup winmsg
+ \brief
+ */
+#define CONTROL_SELECT_ITEM(controlID,iItem) \
+do { \
+ CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), controlID,iItem); \
+ OnMessage(msg); \
+} while(0)
+
+/*!
+ \ingroup winmsg
+ \brief Set the label of the current control
+ */
+#define SET_CONTROL_LABEL(controlID,label) \
+do { \
+ CGUIMessage msg(GUI_MSG_LABEL_SET, GetID(), controlID); \
+ msg.SetLabel(label); \
+ OnMessage(msg); \
+} while(0)
+
+/*!
+ \ingroup winmsg
+ \brief Set the second label of the current control
+ */
+#define SET_CONTROL_LABEL2(controlID,label) \
+do { \
+ CGUIMessage msg(GUI_MSG_LABEL2_SET, GetID(), controlID); \
+ msg.SetLabel(label); \
+ OnMessage(msg); \
+} while(0)
+
+/*!
+ \ingroup winmsg
+ \brief
+ */
+#define SET_CONTROL_HIDDEN(controlID) \
+do { \
+ CGUIMessage msg(GUI_MSG_HIDDEN, GetID(), controlID); \
+ OnMessage(msg); \
+} while(0)
+
+/*!
+ \ingroup winmsg
+ \brief
+ */
+#define SET_CONTROL_FOCUS(controlID, dwParam) \
+do { \
+ CGUIMessage msg(GUI_MSG_SETFOCUS, GetID(), controlID, dwParam); \
+ OnMessage(msg); \
+} while(0)
+
+/*!
+ \ingroup winmsg
+ \brief
+ */
+#define SET_CONTROL_VISIBLE(controlID) \
+do { \
+ CGUIMessage msg(GUI_MSG_VISIBLE, GetID(), controlID); \
+ OnMessage(msg); \
+} while(0)
+
+#define SET_CONTROL_SELECTED(dwSenderId, controlID, bSelect) \
+do { \
+ CGUIMessage msg(bSelect?GUI_MSG_SELECTED:GUI_MSG_DESELECTED, dwSenderId, controlID); \
+ OnMessage(msg); \
+} while(0)
+
+#define BIND_CONTROL(i,c,pv) \
+do { \
+ pv = ((c*)GetControl(i));\
+} while(0)
+
+/*!
+\ingroup winmsg
+\brief Click message sent from controls to windows.
+ */
+#define SEND_CLICK_MESSAGE(id, parentID, action) \
+do { \
+ CGUIMessage msg(GUI_MSG_CLICKED, id, parentID, action); \
+ SendWindowMessage(msg); \
+} while(0)
+
+#include <vector>
+#include "boost/shared_ptr.hpp"
+#include "StdString.h"
+
+// forwards
+class CGUIListItem; typedef boost::shared_ptr<CGUIListItem> CGUIListItemPtr;
+class CFileItemList;
+class CVisualisation;
+
+/*!
+ \ingroup winmsg
+ \brief
+ */
+class CGUIMessage
+{
+public:
+ CGUIMessage(int dwMsg, int senderID, int controlID, int param1 = 0, int param2 = 0);
+ CGUIMessage(int msg, int senderID, int controlID, int param1, int param2, CFileItemList* item);
+ CGUIMessage(int msg, int senderID, int controlID, int param1, int param2, const CGUIListItemPtr &item);
+ CGUIMessage(int msg, int senderID, int controlID, int param1, int param2, CVisualisation* vis);
+ CGUIMessage(const CGUIMessage& msg);
+ virtual ~CGUIMessage(void);
+ const CGUIMessage& operator = (const CGUIMessage& msg);
+
+ int GetControlId() const ;
+ int GetMessage() const;
+ void* GetPointer() const;
+ CGUIListItemPtr GetItem() const;
+ int GetParam1() const;
+ int GetParam2() const;
+ int GetSenderId() const;
+ void SetParam1(int param1);
+ void SetParam2(int param2);
+ void SetPointer(void* pointer);
+ void SetLabel(const std::string& strLabel);
+ void SetLabel(int iString); // for convience - looks up in strings.xml
+ const std::string& GetLabel() const;
+ void SetStringParam(const CStdString &strParam);
+ void SetStringParams(const std::vector<CStdString> &params);
+ const CStdString& GetStringParam(size_t param = 0) const;
+ size_t GetNumStringParams() const;
+ void SetAction(const CGUIActionDescriptor& action);
+ const CGUIActionDescriptor& GetAction() const;
+
+private:
+ std::string m_strLabel;
+ std::vector<CStdString> m_params;
+ CGUIActionDescriptor m_action;
+ int m_senderID;
+ int m_controlID;
+ int m_message;
+ void* m_pointer;
+ int m_param1;
+ int m_param2;
+ CGUIListItemPtr m_item;
+
+ static CStdString empty_string;
+};
+#endif
diff --git a/guilib/GUIMoverControl.cpp b/guilib/GUIMoverControl.cpp
new file mode 100644
index 0000000000..098e890d8f
--- /dev/null
+++ b/guilib/GUIMoverControl.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIMoverControl.h"
+#include "GUIWindowManager.h"
+#include "MouseStat.h"
+#include "Key.h"
+
+// time to reset accelerated cursors (digital movement)
+#define MOVE_TIME_OUT 500L
+
+CGUIMoverControl::CGUIMoverControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+ , m_imgFocus(posX, posY, width, height, textureFocus)
+ , m_imgNoFocus(posX, posY, width, height, textureNoFocus)
+{
+ m_dwFrameCounter = 0;
+ m_dwLastMoveTime = 0;
+ m_fSpeed = 1.0;
+ m_fAnalogSpeed = 2.0f; // TODO: implement correct analog speed
+ m_fAcceleration = 0.2f; // TODO: implement correct computation of acceleration
+ m_fMaxSpeed = 10.0; // TODO: implement correct computation of maxspeed
+ ControlType = GUICONTROL_MOVER;
+ SetLimits(0, 0, 720, 576); // defaults
+ SetLocation(0, 0, false); // defaults
+}
+
+CGUIMoverControl::~CGUIMoverControl(void)
+{}
+
+void CGUIMoverControl::Render()
+{
+ if (m_bInvalidated)
+ {
+ m_imgFocus.SetWidth(m_width);
+ m_imgFocus.SetHeight(m_height);
+
+ m_imgNoFocus.SetWidth(m_width);
+ m_imgNoFocus.SetHeight(m_height);
+ }
+ if (HasFocus())
+ {
+ DWORD dwAlphaCounter = m_dwFrameCounter + 2;
+ DWORD dwAlphaChannel;
+ if ((dwAlphaCounter % 128) >= 64)
+ dwAlphaChannel = dwAlphaCounter % 64;
+ else
+ dwAlphaChannel = 63 - (dwAlphaCounter % 64);
+
+ dwAlphaChannel += 192;
+ SetAlpha( (unsigned char)dwAlphaChannel );
+ m_imgFocus.SetVisible(true);
+ m_imgNoFocus.SetVisible(false);
+ m_dwFrameCounter++;
+ }
+ else
+ {
+ SetAlpha(0xff);
+ m_imgFocus.SetVisible(false);
+ m_imgNoFocus.SetVisible(true);
+ }
+ // render both so the visibility settings cause the frame counter to resetcorrectly
+ m_imgFocus.Render();
+ m_imgNoFocus.Render();
+ CGUIControl::Render();
+}
+
+bool CGUIMoverControl::OnAction(const CAction &action)
+{
+ if (action.id == ACTION_SELECT_ITEM)
+ {
+ // button selected - send message to parent
+ CGUIMessage message(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(message);
+ return true;
+ }
+ if (action.id == ACTION_ANALOG_MOVE)
+ {
+ // if (m_dwAllowedDirections == ALLOWED_DIRECTIONS_UPDOWN)
+ // Move(0, (int)(-m_fAnalogSpeed*action.amount2));
+ // else if (m_dwAllowedDirections == ALLOWED_DIRECTIONS_LEFTRIGHT)
+ // Move((int)(m_fAnalogSpeed*action.amount1), 0);
+ // else // ALLOWED_DIRECTIONS_ALL
+ Move((int)(m_fAnalogSpeed*action.amount1), (int)( -m_fAnalogSpeed*action.amount2));
+ return true;
+ }
+ // base class
+ return CGUIControl::OnAction(action);
+}
+
+void CGUIMoverControl::OnUp()
+{
+ // if (m_dwAllowedDirections == ALLOWED_DIRECTIONS_LEFTRIGHT) return;
+ UpdateSpeed(DIRECTION_UP);
+ Move(0, (int) - m_fSpeed);
+}
+
+void CGUIMoverControl::OnDown()
+{
+ // if (m_dwAllowedDirections == ALLOWED_DIRECTIONS_LEFTRIGHT) return;
+ UpdateSpeed(DIRECTION_DOWN);
+ Move(0, (int)m_fSpeed);
+}
+
+void CGUIMoverControl::OnLeft()
+{
+ // if (m_dwAllowedDirections == ALLOWED_DIRECTIONS_UPDOWN) return;
+ UpdateSpeed(DIRECTION_LEFT);
+ Move((int) - m_fSpeed, 0);
+}
+
+void CGUIMoverControl::OnRight()
+{
+ // if (m_dwAllowedDirections == ALLOWED_DIRECTIONS_UPDOWN) return;
+ UpdateSpeed(DIRECTION_RIGHT);
+ Move((int)m_fSpeed, 0);
+}
+
+bool CGUIMoverControl::OnMouseDrag(const CPoint &offset, const CPoint &point)
+{
+ g_Mouse.SetState(MOUSE_STATE_DRAG);
+ g_Mouse.SetExclusiveAccess(GetID(), GetParentID(), point);
+ Move((int)offset.x, (int)offset.y);
+ return true;
+}
+
+bool CGUIMoverControl::OnMouseClick(int button, const CPoint &point)
+{
+ if (button != MOUSE_LEFT_BUTTON) return false;
+ g_Mouse.EndExclusiveAccess(GetID(), GetParentID());
+ return true;
+}
+
+void CGUIMoverControl::UpdateSpeed(int nDirection)
+{
+ if (timeGetTime() - m_dwLastMoveTime > MOVE_TIME_OUT)
+ {
+ m_fSpeed = 1;
+ m_nDirection = DIRECTION_NONE;
+ }
+ m_dwLastMoveTime = timeGetTime();
+ if (nDirection == m_nDirection)
+ { // accelerate
+ m_fSpeed += m_fAcceleration;
+ if (m_fSpeed > m_fMaxSpeed) m_fSpeed = m_fMaxSpeed;
+ }
+ else
+ { // reset direction and speed
+ m_fSpeed = 1;
+ m_nDirection = nDirection;
+ }
+}
+
+void CGUIMoverControl::AllocResources()
+{
+ CGUIControl::AllocResources();
+ m_dwFrameCounter = 0;
+ m_imgFocus.AllocResources();
+ m_imgNoFocus.AllocResources();
+ float width = m_width ? m_width : m_imgFocus.GetWidth();
+ float height = m_height ? m_height : m_imgFocus.GetHeight();
+ SetWidth(width);
+ SetHeight(height);
+}
+
+void CGUIMoverControl::FreeResources()
+{
+ CGUIControl::FreeResources();
+ m_imgFocus.FreeResources();
+ m_imgNoFocus.FreeResources();
+}
+
+void CGUIMoverControl::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+ m_imgFocus.DynamicResourceAlloc(bOnOff);
+ m_imgNoFocus.DynamicResourceAlloc(bOnOff);
+}
+
+void CGUIMoverControl::Move(int iX, int iY)
+{
+ int iLocX = m_iLocationX + iX;
+ int iLocY = m_iLocationY + iY;
+ // check if we are within the bounds
+ if (iLocX < m_iX1) iLocX = m_iX1;
+ if (iLocY < m_iY1) iLocY = m_iY1;
+ if (iLocX > m_iX2) iLocX = m_iX2;
+ if (iLocY > m_iY2) iLocY = m_iY2;
+ // ok, now set the location of the mover
+ SetLocation(iLocX, iLocY);
+}
+
+void CGUIMoverControl::SetLocation(int iLocX, int iLocY, bool bSetPosition)
+{
+ if (bSetPosition) SetPosition(GetXPosition() + iLocX - m_iLocationX, GetYPosition() + iLocY - m_iLocationY);
+ m_iLocationX = iLocX;
+ m_iLocationY = iLocY;
+}
+
+void CGUIMoverControl::SetPosition(float posX, float posY)
+{
+ CGUIControl::SetPosition(posX, posY);
+ m_imgFocus.SetPosition(posX, posY);
+ m_imgNoFocus.SetPosition(posX, posY);
+}
+
+void CGUIMoverControl::SetAlpha(unsigned char alpha)
+{
+ m_imgFocus.SetAlpha(alpha);
+ m_imgNoFocus.SetAlpha(alpha);
+}
+
+void CGUIMoverControl::UpdateColors()
+{
+ CGUIControl::UpdateColors();
+ m_imgFocus.SetDiffuseColor(m_diffuseColor);
+ m_imgNoFocus.SetDiffuseColor(m_diffuseColor);
+}
+
+void CGUIMoverControl::SetLimits(int iX1, int iY1, int iX2, int iY2)
+{
+ m_iX1 = iX1;
+ m_iY1 = iY1;
+ m_iX2 = iX2;
+ m_iY2 = iY2;
+}
diff --git a/guilib/GUIMoverControl.h b/guilib/GUIMoverControl.h
new file mode 100644
index 0000000000..5cda5a0590
--- /dev/null
+++ b/guilib/GUIMoverControl.h
@@ -0,0 +1,97 @@
+/*!
+\file GUIMoverControl.h
+\brief
+*/
+
+#ifndef GUILIB_GUIMoverCONTROL_H
+#define GUILIB_GUIMoverCONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUITexture.h"
+#include "GUIControl.h"
+
+#define ALLOWED_DIRECTIONS_ALL 0
+#define ALLOWED_DIRECTIONS_UPDOWN 1
+#define ALLOWED_DIRECTIONS_LEFTRIGHT 2
+
+#define DIRECTION_NONE 0
+#define DIRECTION_UP 1
+#define DIRECTION_DOWN 2
+#define DIRECTION_LEFT 3
+#define DIRECTION_RIGHT 4
+
+// normal alignment is TOP LEFT 0 = topleft, 1 = topright
+#define ALIGN_RIGHT 1
+#define ALIGN_BOTTOM 2
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIMoverControl : public CGUIControl
+{
+public:
+ CGUIMoverControl(int parentID, int controlID,
+ float posX, float posY, float width, float height,
+ const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus);
+
+ virtual ~CGUIMoverControl(void);
+ virtual CGUIMoverControl *Clone() const { return new CGUIMoverControl(*this); };
+
+ virtual void Render();
+ virtual bool OnAction(const CAction &action);
+ virtual void OnUp();
+ virtual void OnDown();
+ virtual void OnLeft();
+ virtual void OnRight();
+ virtual bool OnMouseDrag(const CPoint &offset, const CPoint &point);
+ virtual bool OnMouseClick(int button, const CPoint &point);
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual void SetPosition(float posX, float posY);
+ void SetLimits(int iX1, int iY1, int iX2, int iY2);
+ void SetLocation(int iLocX, int iLocY, bool bSetPosition = true);
+ int GetXLocation() const { return m_iLocationX;};
+ int GetYLocation() const { return m_iLocationY;};
+
+protected:
+ virtual void UpdateColors();
+ void SetAlpha(unsigned char alpha);
+ void UpdateSpeed(int nDirection);
+ void Move(int iX, int iY);
+ CGUITexture m_imgFocus;
+ CGUITexture m_imgNoFocus;
+ DWORD m_dwFrameCounter;
+ DWORD m_dwLastMoveTime;
+ int m_nDirection;
+ float m_fSpeed;
+ float m_fAnalogSpeed;
+ float m_fMaxSpeed;
+ float m_fAcceleration;
+ int m_iX1, m_iX2, m_iY1, m_iY2;
+ int m_iLocationX, m_iLocationY;
+};
+#endif
diff --git a/guilib/GUIMultiImage.cpp b/guilib/GUIMultiImage.cpp
new file mode 100644
index 0000000000..75db87e921
--- /dev/null
+++ b/guilib/GUIMultiImage.cpp
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIMultiImage.h"
+#include "TextureManager.h"
+#include "FileSystem/Directory.h"
+#include "Util.h"
+#include "FileItem.h"
+#include "Key.h"
+
+using namespace std;
+using namespace DIRECTORY;
+
+CGUIMultiImage::CGUIMultiImage(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& texture, DWORD timePerImage, DWORD fadeTime, bool randomized, bool loop, DWORD timeToPauseAtEnd)
+ : CGUIControl(parentID, controlID, posX, posY, width, height),
+ m_image(0, 0, posX, posY, width, height, texture)
+{
+ m_currentImage = 0;
+ m_timePerImage = timePerImage + fadeTime;
+ m_timeToPauseAtEnd = timeToPauseAtEnd;
+ m_image.SetCrossFade(fadeTime);
+ m_randomized = randomized;
+ m_loop = loop;
+ ControlType = GUICONTROL_MULTI_IMAGE;
+ m_bDynamicResourceAlloc=false;
+ m_directoryLoaded = false;
+}
+
+CGUIMultiImage::CGUIMultiImage(const CGUIMultiImage &from)
+: CGUIControl(from), m_image(from.m_image)
+{
+ m_texturePath = from.m_texturePath;
+ m_timePerImage = from.m_timePerImage;
+ m_timeToPauseAtEnd = from.m_timeToPauseAtEnd;
+ m_randomized = from.m_randomized;
+ m_loop = from.m_loop;
+ m_bDynamicResourceAlloc=false;
+ m_directoryLoaded = false;
+ if (m_texturePath.IsConstant())
+ m_currentPath = m_texturePath.GetLabel(WINDOW_INVALID);
+ m_currentImage = 0;
+ ControlType = GUICONTROL_MULTI_IMAGE;
+}
+
+CGUIMultiImage::~CGUIMultiImage(void)
+{
+}
+
+void CGUIMultiImage::UpdateVisibility(const CGUIListItem *item)
+{
+ CGUIControl::UpdateVisibility(item);
+
+ // check if we're hidden, and deallocate if so
+ if (!IsVisible() && m_visible != DELAYED)
+ {
+ if (m_bDynamicResourceAlloc && m_bAllocated)
+ FreeResources();
+ return;
+ }
+
+ // we are either delayed or visible, so we can allocate our resources
+ if (!m_directoryLoaded)
+ {
+ LoadDirectory();
+ m_image.SetFileName(m_files.size() ? m_files[0] : "");
+ }
+ if (!m_bAllocated)
+ AllocResources();
+}
+
+void CGUIMultiImage::UpdateInfo(const CGUIListItem *item)
+{
+ // check for conditional information before we
+ // alloc as this can free our resources
+ if (!m_texturePath.IsConstant())
+ {
+ CStdString texturePath(m_texturePath.GetLabel(m_parentID));
+ if (texturePath != m_currentPath && !texturePath.IsEmpty())
+ {
+ // a new path - set our current path and tell ourselves to load our directory
+ m_currentPath = texturePath;
+ m_directoryLoaded = false;
+ }
+ }
+}
+
+void CGUIMultiImage::Render()
+{
+ if (!m_files.empty())
+ {
+ // Set a viewport so that we don't render outside the defined area
+ g_graphicsContext.SetClipRegion(m_posX, m_posY, m_width, m_height);
+
+ unsigned int nextImage = m_currentImage + 1;
+ if (nextImage >= m_files.size())
+ nextImage = m_loop ? 0 : m_currentImage; // stay on the last image if <loop>no</loop>
+
+ if (nextImage != m_currentImage)
+ {
+ // check if we should be loading a new image yet
+ DWORD timeToShow = m_timePerImage;
+ if (0 == nextImage) // last image should be paused for a bit longer if that's what the skinner wishes.
+ timeToShow += m_timeToPauseAtEnd;
+ if (m_imageTimer.IsRunning() && m_imageTimer.GetElapsedMilliseconds() > timeToShow)
+ {
+ // grab a new image
+ m_currentImage = nextImage;
+ m_image.SetFileName(m_files[m_currentImage]);
+ m_imageTimer.StartZero();
+ }
+ }
+ m_image.SetColorDiffuse(m_diffuseColor);
+ m_image.Render();
+ g_graphicsContext.RestoreClipRegion();
+ }
+ CGUIControl::Render();
+}
+
+bool CGUIMultiImage::OnAction(const CAction &action)
+{
+ return false;
+}
+
+bool CGUIMultiImage::OnMessage(CGUIMessage &message)
+{
+ if (message.GetMessage() == GUI_MSG_REFRESH_THUMBS)
+ {
+ if (!m_texturePath.IsConstant())
+ FreeResources();
+ return true;
+ }
+ return CGUIControl::OnMessage(message);
+}
+
+void CGUIMultiImage::AllocResources()
+{
+ FreeResources();
+ CGUIControl::AllocResources();
+
+ if (!m_directoryLoaded)
+ LoadDirectory();
+
+ // Load in the current image, and reset our timer
+ m_currentImage = 0;
+ m_imageTimer.StartZero();
+
+ // and re-randomize if our control has been reallocated
+ if (m_randomized)
+ random_shuffle(m_files.begin(), m_files.end());
+
+ m_image.SetFileName(m_files.size() ? m_files[0] : "");
+}
+
+void CGUIMultiImage::FreeResources()
+{
+ m_image.FreeResources();
+ m_currentImage = 0;
+ CGUIControl::FreeResources();
+}
+
+void CGUIMultiImage::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+ m_bDynamicResourceAlloc=bOnOff;
+}
+
+bool CGUIMultiImage::CanFocus() const
+{
+ return false;
+}
+
+void CGUIMultiImage::SetAspectRatio(const CAspectRatio &ratio)
+{
+ m_image.SetAspectRatio(ratio);
+}
+
+void CGUIMultiImage::LoadDirectory()
+{
+ // Load any images from our texture bundle first
+ m_files.clear();
+
+ // don't load any images if our path is empty
+ if (m_currentPath.IsEmpty()) return;
+
+ // check to see if we have a single image or a folder of images
+ CFileItem item(m_currentPath, false);
+ if (item.IsPicture())
+ {
+ m_files.push_back(m_currentPath);
+ }
+ else
+ { // folder of images
+ g_TextureManager.GetBundledTexturesFromPath(m_currentPath, m_files);
+
+ // Load in our images from the directory specified
+ // m_currentPath is relative (as are all skin paths)
+ CStdString realPath = g_TextureManager.GetTexturePath(m_currentPath, true);
+ if (realPath.IsEmpty())
+ return;
+
+ CUtil::AddSlashAtEnd(realPath);
+ CFileItemList items;
+ CDirectory::GetDirectory(realPath, items);
+ for (int i=0; i < items.Size(); i++)
+ {
+ CFileItemPtr pItem = items[i];
+ if (pItem->IsPicture())
+ m_files.push_back(pItem->m_strPath);
+ }
+ }
+
+ // Randomize or sort our images if necessary
+ if (m_randomized)
+ random_shuffle(m_files.begin(), m_files.end());
+ else
+ sort(m_files.begin(), m_files.end());
+
+ // flag as loaded - no point in constantly reloading them
+ m_directoryLoaded = true;
+ m_imageTimer.StartZero();
+}
+
+void CGUIMultiImage::SetInfo(const CGUIInfoLabel &info)
+{
+ m_texturePath = info;
+ if (m_texturePath.IsConstant())
+ m_currentPath = m_texturePath.GetLabel(WINDOW_INVALID);
+}
diff --git a/guilib/GUIMultiImage.h b/guilib/GUIMultiImage.h
new file mode 100644
index 0000000000..60b03d966b
--- /dev/null
+++ b/guilib/GUIMultiImage.h
@@ -0,0 +1,79 @@
+/*!
+\file GUIMultiImage.h
+\brief
+*/
+
+#ifndef GUILIB_GUIMULTIIMAGECONTROL_H
+#define GUILIB_GUIMULTIIMAGECONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIImage.h"
+#include "utils/Stopwatch.h"
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIMultiImage : public CGUIControl
+{
+public:
+ CGUIMultiImage(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& texture, DWORD timePerImage, DWORD fadeTime, bool randomized, bool loop, DWORD timeToPauseAtEnd);
+ CGUIMultiImage(const CGUIMultiImage &from);
+ virtual ~CGUIMultiImage(void);
+ virtual CGUIMultiImage *Clone() const { return new CGUIMultiImage(*this); };
+
+ virtual void Render();
+ virtual void UpdateVisibility(const CGUIListItem *item = NULL);
+ virtual void UpdateInfo(const CGUIListItem *item = NULL);
+ virtual bool OnAction(const CAction &action);
+ virtual bool OnMessage(CGUIMessage &message);
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual bool IsDynamicallyAllocated() { return m_bDynamicResourceAlloc; };
+ virtual bool CanFocus() const;
+
+ void SetInfo(const CGUIInfoLabel &info);
+ void SetAspectRatio(const CAspectRatio &ratio);
+
+protected:
+ void LoadDirectory();
+
+ CGUIInfoLabel m_texturePath;
+ CStdString m_currentPath;
+ unsigned int m_currentImage;
+ CStopWatch m_imageTimer;
+ DWORD m_timePerImage;
+ DWORD m_timeToPauseAtEnd;
+ bool m_randomized;
+ bool m_loop;
+
+ bool m_bDynamicResourceAlloc;
+ bool m_directoryLoaded;
+ std::vector<CStdString> m_files;
+
+ CGUIImage m_image;
+};
+#endif
diff --git a/guilib/GUIMultiSelectText.cpp b/guilib/GUIMultiSelectText.cpp
new file mode 100644
index 0000000000..c2d5d4f9f4
--- /dev/null
+++ b/guilib/GUIMultiSelectText.cpp
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIMultiSelectText.h"
+#include "Key.h"
+#include "MouseStat.h"
+#include "utils/log.h"
+
+using namespace std;
+
+CGUIMultiSelectTextControl::CSelectableString::CSelectableString(CGUIFont *font, const CStdString &text, bool selectable, const CStdString &clickAction)
+ : m_text(font, false)
+{
+ m_selectable = selectable;
+ m_clickAction = clickAction;
+ m_clickAction.TrimLeft(" =");
+ m_clickAction.TrimRight(" ");
+ m_text.Update(text);
+ float height;
+ m_text.GetTextExtent(m_length, height);
+}
+
+CGUIMultiSelectTextControl::CGUIMultiSelectTextControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus, const CLabelInfo& labelInfo, const CGUIInfoLabel &content)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+ , m_button(parentID, controlID, posX, posY, width, height, textureFocus, textureNoFocus, labelInfo)
+{
+ m_info = content;
+ m_label = labelInfo;
+ m_selectedItem = 0;
+ m_offset = 0;
+ m_totalWidth = 0;
+ m_scrollOffset = 0;
+ m_scrollSpeed = 0;
+ m_scrollLastTime = 0;
+ m_renderTime = 0;
+ m_label.align &= ~3; // we currently ignore all x alignment
+}
+
+CGUIMultiSelectTextControl::~CGUIMultiSelectTextControl(void)
+{
+}
+
+void CGUIMultiSelectTextControl::DoRender(DWORD currentTime)
+{
+ m_renderTime = currentTime;
+ CGUIControl::DoRender(currentTime);
+}
+
+void CGUIMultiSelectTextControl::UpdateColors()
+{
+ m_label.UpdateColors();
+ CGUIControl::UpdateColors();
+}
+
+void CGUIMultiSelectTextControl::Render()
+{
+ // check our selected item is in range
+ unsigned int numSelectable = GetNumSelectable();
+ if (!numSelectable)
+ SetFocus(false);
+ else if (m_selectedItem >= numSelectable)
+ m_selectedItem = numSelectable - 1;
+
+ // and validate our offset
+ if (m_offset + m_width > m_totalWidth)
+ m_offset = m_totalWidth - m_width;
+ if (m_offset < 0) m_offset = 0;
+
+ // handle scrolling
+ m_scrollOffset += m_scrollSpeed * (m_renderTime - m_scrollLastTime);
+ if ((m_scrollSpeed < 0 && m_scrollOffset < m_offset) ||
+ (m_scrollSpeed > 0 && m_scrollOffset > m_offset))
+ {
+ m_scrollOffset = m_offset;
+ m_scrollSpeed = 0;
+ }
+ m_scrollLastTime = m_renderTime;
+
+ // clip and set our scrolling origin
+ bool clip(m_width < m_totalWidth);
+ if (clip)
+ { // need to crop
+ if (!g_graphicsContext.SetClipRegion(m_posX, m_posY, m_width, m_height))
+ return; // nothing to render??
+ }
+ g_graphicsContext.SetOrigin(-m_scrollOffset, 0);
+
+ // render the buttons
+ for (unsigned int i = 0; i < m_buttons.size(); i++)
+ {
+ m_buttons[i].SetFocus(HasFocus() && i == m_selectedItem);
+ m_buttons[i].DoRender(m_renderTime);
+ }
+
+ // position the text - we center vertically if applicable, and use the offsets.
+ // all x-alignment is ignored for now (see constructor)
+ float posX = m_posX;
+ float posY = m_posY + m_label.offsetY;
+ if (m_label.align & XBFONT_CENTER_Y)
+ posY = m_posY + m_height * 0.5f;
+
+ if (m_items.size() && m_items[0].m_selectable)
+ posX += m_label.offsetX;
+
+ // render the text
+ unsigned int num_selectable = 0;
+ for (unsigned int i = 0; i < m_items.size(); i++)
+ {
+ CSelectableString &string = m_items[i];
+ if (IsDisabled()) // all text is rendered with disabled color
+ string.m_text.Render(posX, posY, 0, m_label.disabledColor, m_label.shadowColor, m_label.align, 0, true);
+ else if (HasFocus() && string.m_selectable && num_selectable == m_selectedItem) // text is rendered with focusedcolor
+ string.m_text.Render(posX, posY, 0, m_label.focusedColor, m_label.shadowColor, m_label.align, 0);
+ else // text is rendered with textcolor
+ string.m_text.Render(posX, posY, 0, m_label.textColor, m_label.shadowColor, m_label.align, 0);
+ posX += string.m_length;
+ if (string.m_selectable)
+ num_selectable++;
+ }
+
+ g_graphicsContext.RestoreOrigin();
+ if (clip)
+ g_graphicsContext.RestoreClipRegion();
+
+ CGUIControl::Render();
+}
+
+void CGUIMultiSelectTextControl::UpdateInfo(const CGUIListItem *item)
+{
+ if (m_info.IsEmpty())
+ return; // nothing to do
+
+ if (item)
+ UpdateText(m_info.GetItemLabel(item));
+ else
+ UpdateText(m_info.GetLabel(m_parentID));
+}
+
+bool CGUIMultiSelectTextControl::OnAction(const CAction &action)
+{
+ if (action.id == ACTION_SELECT_ITEM)
+ {
+ // item is clicked - see if we have a clickaction
+ CStdString clickAction;
+ unsigned int selected = 0;
+ for (unsigned int i = 0; i < m_items.size(); i++)
+ {
+ if (m_items[i].m_selectable)
+ {
+ if (m_selectedItem == selected)
+ clickAction = m_items[i].m_clickAction;
+ selected++;
+ }
+ }
+ if (!clickAction.IsEmpty())
+ { // have a click action -> perform it
+ CGUIMessage message(GUI_MSG_EXECUTE, m_controlID, m_parentID);
+ message.SetStringParam(clickAction);
+ g_graphicsContext.SendMessage(message);
+ }
+ else
+ { // no click action, just send a message to the window
+ CGUIMessage msg(GUI_MSG_CLICKED, m_controlID, m_parentID, m_selectedItem);
+ SendWindowMessage(msg);
+ }
+ return true;
+ }
+ return CGUIControl::OnAction(action);
+}
+
+void CGUIMultiSelectTextControl::OnLeft()
+{
+ if (MoveLeft())
+ return;
+ CGUIControl::OnLeft();
+}
+
+void CGUIMultiSelectTextControl::OnRight()
+{
+ if (MoveRight())
+ return;
+ CGUIControl::OnRight();
+}
+
+// movement functions (callable from lists)
+bool CGUIMultiSelectTextControl::MoveLeft()
+{
+ if (m_selectedItem > 0)
+ ScrollToItem(m_selectedItem - 1);
+ else if (GetNumSelectable() && m_controlLeft && m_controlLeft == m_controlID)
+ ScrollToItem(GetNumSelectable() - 1);
+ else
+ return false;
+ return true;
+}
+
+bool CGUIMultiSelectTextControl::MoveRight()
+{
+ if (GetNumSelectable() && m_selectedItem < GetNumSelectable() - 1)
+ ScrollToItem(m_selectedItem + 1);
+ else if (m_controlRight && m_controlRight == m_controlID)
+ ScrollToItem(0);
+ else
+ return false;
+ return true;
+}
+
+void CGUIMultiSelectTextControl::SelectItemFromPoint(const CPoint &point)
+{
+ int item = GetItemFromPoint(point);
+ if (item != -1)
+ {
+ ScrollToItem(item);
+ SetFocus(true);
+ }
+ else
+ SetFocus(false);
+}
+
+bool CGUIMultiSelectTextControl::HitTest(const CPoint &point) const
+{
+ return (GetItemFromPoint(point) != -1);
+}
+
+bool CGUIMultiSelectTextControl::OnMouseOver(const CPoint &point)
+{
+ ScrollToItem(GetItemFromPoint(point));
+ return CGUIControl::OnMouseOver(point);
+}
+
+bool CGUIMultiSelectTextControl::OnMouseClick(int button, const CPoint &point)
+{
+ if (button == MOUSE_LEFT_BUTTON)
+ {
+ m_selectedItem = GetItemFromPoint(point);
+ g_Mouse.SetState(MOUSE_STATE_CLICK);
+ CAction action;
+ action.id = ACTION_SELECT_ITEM;
+ OnAction(action);
+ return true;
+ }
+ return false;
+}
+
+int CGUIMultiSelectTextControl::GetItemFromPoint(const CPoint &point) const
+{
+ if (!m_label.font) return -1;
+ float posX = m_posX;
+ unsigned int selectable = 0;
+ for (unsigned int i = 0; i < m_items.size(); i++)
+ {
+ const CSelectableString &string = m_items[i];
+ if (string.m_selectable)
+ {
+ CRect rect(posX, m_posY, posX + string.m_length, m_posY + m_height);
+ if (rect.PtInRect(point))
+ return selectable;
+ selectable++;
+ }
+ posX += string.m_length;
+ }
+ return -1;
+}
+
+void CGUIMultiSelectTextControl::UpdateText(const CStdString &text)
+{
+ if (text == m_oldText)
+ return;
+
+ m_items.clear();
+
+ // parse our text into clickable blocks
+ // format is [ONCLICK <action>] [/ONCLICK]
+ size_t startClickable = text.Find("[ONCLICK");
+ size_t startUnclickable = 0;
+
+ // add the first unclickable block
+ if (startClickable != CStdString::npos)
+ AddString(text.Mid(startUnclickable, startClickable - startUnclickable), false);
+ else
+ AddString(text.Mid(startUnclickable), false);
+ while (startClickable != CStdString::npos)
+ {
+ // grep out the action and the end of the string
+ size_t endAction = text.Find(']', startClickable + 8);
+ size_t endClickable = text.Find("[/ONCLICK]", startClickable + 8);
+ if (endAction != CStdString::npos && endClickable != CStdString::npos)
+ { // success - add the string, and move the start of our next unclickable portion along
+ AddString(text.Mid(endAction + 1, endClickable - endAction - 1), true, text.Mid(startClickable + 8, endAction - startClickable - 8));
+ startUnclickable = endClickable + 10;
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "Invalid multiselect string %s", text.c_str());
+ break;
+ }
+ startClickable = text.Find("[ONCLICK", startUnclickable);
+ // add the unclickable portion
+ if (startClickable != CStdString::npos)
+ AddString(text.Mid(startUnclickable, startClickable - startUnclickable), false);
+ else
+ AddString(text.Mid(startUnclickable), false);
+ }
+
+ m_oldText = text;
+
+ // finally, position our buttons
+ PositionButtons();
+}
+
+void CGUIMultiSelectTextControl::AddString(const CStdString &text, bool selectable, const CStdString &clickAction)
+{
+ if (!text.IsEmpty())
+ m_items.push_back(CSelectableString(m_label.font, text, selectable, clickAction));
+}
+
+void CGUIMultiSelectTextControl::PositionButtons()
+{
+ m_buttons.clear();
+
+ // add new buttons
+ m_totalWidth = 0;
+ if (m_items.size() && m_items.front().m_selectable)
+ m_totalWidth += m_label.offsetX;
+
+ for (unsigned int i = 0; i < m_items.size(); i++)
+ {
+ const CSelectableString &text = m_items[i];
+ if (text.m_selectable)
+ {
+ CGUIButtonControl button(m_button);
+ button.SetPosition(m_posX + m_totalWidth - m_label.offsetX, m_posY);
+ button.SetWidth(text.m_length + 2 * m_label.offsetX);
+ m_buttons.push_back(button);
+ }
+ m_totalWidth += text.m_length;
+ }
+
+ if (m_items.size() && m_items.back().m_selectable)
+ m_totalWidth += m_label.offsetX;
+}
+
+CStdString CGUIMultiSelectTextControl::GetDescription() const
+{
+ // We currently just return the entire string - should we bother returning the
+ // particular subitems of this?
+ CStdString strLabel(m_info.GetLabel(m_parentID));
+ return strLabel;
+}
+
+unsigned int CGUIMultiSelectTextControl::GetNumSelectable() const
+{
+ unsigned int selectable = 0;
+ for (unsigned int i = 0; i < m_items.size(); i++)
+ if (m_items[i].m_selectable)
+ selectable++;
+ return selectable;
+}
+
+unsigned int CGUIMultiSelectTextControl::GetFocusedItem() const
+{
+ if (GetNumSelectable())
+ return m_selectedItem + 1;
+ return 0;
+}
+
+void CGUIMultiSelectTextControl::SetFocusedItem(unsigned int item)
+{
+ SetFocus(item > 0);
+ if (item > 0)
+ ScrollToItem(item - 1);
+}
+
+bool CGUIMultiSelectTextControl::CanFocus() const
+{
+ if (!GetNumSelectable()) return false;
+ return CGUIControl::CanFocus();
+}
+
+void CGUIMultiSelectTextControl::SetFocus(bool focus)
+{
+ for (unsigned int i = 0; i < m_buttons.size(); i++)
+ m_buttons[i].SetFocus(focus);
+ CGUIControl::SetFocus(focus);
+}
+
+// overrides to allow anims to translate down to the focus image
+void CGUIMultiSelectTextControl::SetAnimations(const vector<CAnimation> &animations)
+{
+ // send any focus animations down to the focus image only
+ m_animations.clear();
+ vector<CAnimation> focusAnims;
+ for (unsigned int i = 0; i < animations.size(); i++)
+ {
+ const CAnimation &anim = animations[i];
+ if (anim.GetType() == ANIM_TYPE_FOCUS)
+ focusAnims.push_back(anim);
+ else
+ m_animations.push_back(anim);
+ }
+ m_button.SetAnimations(focusAnims);
+}
+
+void CGUIMultiSelectTextControl::ScrollToItem(unsigned int item)
+{
+ static const unsigned int time_to_scroll = 200;
+ if (item >= m_buttons.size()) return;
+ // grab our button
+ const CGUIButtonControl &button = m_buttons[item];
+ float left = button.GetXPosition();
+ float right = left + button.GetWidth();
+ // make sure that we scroll so that this item is on screen
+ m_scrollOffset = m_offset;
+ if (left < m_posX + m_offset)
+ m_offset = left - m_posX;
+ else if (right > m_posX + m_offset + m_width)
+ m_offset = right - m_width - m_posX;
+ m_scrollSpeed = (m_offset - m_scrollOffset) / time_to_scroll;
+ m_selectedItem = item;
+}
+
diff --git a/guilib/GUIMultiSelectText.h b/guilib/GUIMultiSelectText.h
new file mode 100644
index 0000000000..56e3d7a905
--- /dev/null
+++ b/guilib/GUIMultiSelectText.h
@@ -0,0 +1,102 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUILabelControl.h" // for CInfoPortion
+#include "GUIButtonControl.h"
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIMultiSelectTextControl : public CGUIControl
+{
+public:
+ CGUIMultiSelectTextControl(int parentID, int controlID,
+ float posX, float posY, float width, float height,
+ const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus, const CLabelInfo &label, const CGUIInfoLabel &content);
+
+ virtual ~CGUIMultiSelectTextControl(void);
+ virtual CGUIMultiSelectTextControl *Clone() const { return new CGUIMultiSelectTextControl(*this); };
+
+ virtual void DoRender(DWORD currentTime);
+ virtual void Render();
+
+ virtual bool OnAction(const CAction &action);
+ virtual void OnLeft();
+ virtual void OnRight();
+ virtual bool HitTest(const CPoint &point) const;
+ virtual bool OnMouseOver(const CPoint &point);
+ virtual bool OnMouseClick(int button, const CPoint &point);
+ virtual void UpdateInfo(const CGUIListItem *item = NULL);
+
+ virtual CStdString GetDescription() const;
+ virtual bool CanFocus() const;
+
+ void UpdateText(const CStdString &text);
+ bool MoveLeft();
+ bool MoveRight();
+ void SelectItemFromPoint(const CPoint &point);
+ unsigned int GetFocusedItem() const;
+ void SetFocusedItem(unsigned int item);
+
+ // overrides to allow all focus anims to translate down to the focus image
+ virtual void SetAnimations(const std::vector<CAnimation> &animations);
+ virtual void SetFocus(bool focus);
+protected:
+ virtual void UpdateColors();
+ void AddString(const CStdString &text, bool selectable, const CStdString &clickAction = "");
+ void PositionButtons();
+ unsigned int GetNumSelectable() const;
+ int GetItemFromPoint(const CPoint &point) const;
+ void ScrollToItem(unsigned int item);
+
+ // the static strings and buttons strings
+ class CSelectableString
+ {
+ public:
+ CSelectableString(CGUIFont *font, const CStdString &text, bool selectable, const CStdString &clickAction);
+ CGUITextLayout m_text;
+ float m_length;
+ bool m_selectable;
+ CStdString m_clickAction;
+ };
+ std::vector<CSelectableString> m_items;
+
+ CLabelInfo m_label;
+ CGUIInfoLabel m_info;
+ CStdString m_oldText;
+ DWORD m_renderTime;
+
+ // scrolling
+ float m_totalWidth;
+ float m_offset;
+ float m_scrollOffset;
+ float m_scrollSpeed;
+ DWORD m_scrollLastTime;
+
+ // buttons
+ CGUIButtonControl m_button;
+ unsigned int m_selectedItem;
+ std::vector<CGUIButtonControl> m_buttons;
+};
+
diff --git a/guilib/GUIPanelContainer.cpp b/guilib/GUIPanelContainer.cpp
new file mode 100644
index 0000000000..6d5b12d5a0
--- /dev/null
+++ b/guilib/GUIPanelContainer.cpp
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIPanelContainer.h"
+#include "GUIListItem.h"
+#include "utils/GUIInfoManager.h"
+#include "Key.h"
+
+using namespace std;
+
+CGUIPanelContainer::CGUIPanelContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, int scrollTime, int preloadItems)
+ : CGUIBaseContainer(parentID, controlID, posX, posY, width, height, orientation, scrollTime, preloadItems)
+{
+ ControlType = GUICONTAINER_PANEL;
+ m_type = VIEW_TYPE_ICON;
+ m_itemsPerRow = 1;
+}
+
+CGUIPanelContainer::~CGUIPanelContainer(void)
+{
+}
+
+void CGUIPanelContainer::Render()
+{
+ ValidateOffset();
+
+ if (m_bInvalidated)
+ UpdateLayout();
+
+ if (!m_layout || !m_focusedLayout) return;
+
+ UpdateScrollOffset();
+
+ int offset = (int)(m_scrollOffset / m_layout->Size(m_orientation));
+
+ int cacheBefore, cacheAfter;
+ GetCacheOffsets(cacheBefore, cacheAfter);
+
+ // Free memory not used on screen at the moment, do this first so there's more memory for the new items.
+ FreeMemory(CorrectOffset(offset - cacheBefore, 0), CorrectOffset(offset + cacheAfter + m_itemsPerPage + 1, 0));
+
+ g_graphicsContext.SetClipRegion(m_posX, m_posY, m_width, m_height);
+ float pos = (m_orientation == VERTICAL) ? m_posY : m_posX;
+ float end = (m_orientation == VERTICAL) ? m_posY + m_height : m_posX + m_width;
+ pos += (offset - cacheBefore) * m_layout->Size(m_orientation) - m_scrollOffset;
+ end += cacheAfter * m_layout->Size(m_orientation);
+
+ float focusedPos = 0;
+ int focusedCol = 0;
+ CGUIListItemPtr focusedItem;
+ int current = (offset - cacheBefore) * m_itemsPerRow;
+ int col = 0;
+ while (pos < end && m_items.size())
+ {
+ if (current >= (int)m_items.size())
+ break;
+ if (current >= 0)
+ {
+ CGUIListItemPtr item = m_items[current];
+ bool focused = (current == m_offset * m_itemsPerRow + m_cursor) && m_bHasFocus;
+ // render our item
+ if (focused)
+ {
+ focusedPos = pos;
+ focusedCol = col;
+ focusedItem = item;
+ }
+ else
+ {
+ if (m_orientation == VERTICAL)
+ RenderItem(m_posX + col * m_layout->Size(HORIZONTAL), pos, item.get(), false);
+ else
+ RenderItem(pos, m_posY + col * m_layout->Size(VERTICAL), item.get(), false);
+ }
+ }
+ // increment our position
+ if (col < m_itemsPerRow - 1)
+ col++;
+ else
+ {
+ pos += m_layout->Size(m_orientation);
+ col = 0;
+ }
+ current++;
+ }
+ // and render the focused item last (for overlapping purposes)
+ if (focusedItem)
+ {
+ if (m_orientation == VERTICAL)
+ RenderItem(m_posX + focusedCol * m_layout->Size(HORIZONTAL), focusedPos, focusedItem.get(), true);
+ else
+ RenderItem(focusedPos, m_posY + focusedCol * m_layout->Size(VERTICAL), focusedItem.get(), true);
+ }
+
+ g_graphicsContext.RestoreClipRegion();
+
+ UpdatePageControl(offset);
+
+ CGUIControl::Render();
+}
+
+bool CGUIPanelContainer::OnAction(const CAction &action)
+{
+ switch (action.id)
+ {
+ case ACTION_PAGE_UP:
+ {
+ if (m_offset == 0)
+ { // already on the first page, so move to the first item
+ SetCursor(0);
+ }
+ else
+ { // scroll up to the previous page
+ Scroll( -m_itemsPerPage);
+ }
+ return true;
+ }
+ break;
+ case ACTION_PAGE_DOWN:
+ {
+ if ((m_offset + m_itemsPerPage) * m_itemsPerRow >= (int)m_items.size() || (int)m_items.size() < m_itemsPerPage)
+ { // already at the last page, so move to the last item.
+ SetCursor(m_items.size() - m_offset * m_itemsPerRow - 1);
+ }
+ else
+ { // scroll down to the next page
+ Scroll(m_itemsPerPage);
+ }
+ return true;
+ }
+ break;
+ // smooth scrolling (for analog controls)
+ case ACTION_SCROLL_UP:
+ {
+ m_analogScrollCount += action.amount1 * action.amount1;
+ bool handled = false;
+ while (m_analogScrollCount > AnalogScrollSpeed())
+ {
+ handled = true;
+ m_analogScrollCount -= AnalogScrollSpeed();
+ if (m_offset > 0)// && m_cursor <= m_itemsPerPage * m_itemsPerRow / 2)
+ {
+ Scroll(-1);
+ }
+ else if (m_cursor > 0)
+ {
+ SetCursor(m_cursor - 1);
+ }
+ }
+ return handled;
+ }
+ break;
+ case ACTION_SCROLL_DOWN:
+ {
+ m_analogScrollCount += action.amount1 * action.amount1;
+ bool handled = false;
+ while (m_analogScrollCount > AnalogScrollSpeed())
+ {
+ handled = true;
+ m_analogScrollCount -= AnalogScrollSpeed();
+ if ((m_offset + m_itemsPerPage) * m_itemsPerRow < (int)m_items.size())// && m_cursor >= m_itemsPerPage * m_itemsPerRow / 2)
+ {
+ Scroll(1);
+ }
+ else if (m_cursor < m_itemsPerPage * m_itemsPerRow - 1 && m_offset * m_itemsPerRow + m_cursor < (int)m_items.size() - 1)
+ {
+ SetCursor(m_cursor + 1);
+ }
+ }
+ return handled;
+ }
+ break;
+ }
+ return CGUIBaseContainer::OnAction(action);
+}
+
+bool CGUIPanelContainer::OnMessage(CGUIMessage& message)
+{
+ if (message.GetControlId() == GetID() )
+ {
+ if (message.GetMessage() == GUI_MSG_LABEL_RESET)
+ {
+ SetCursor(0);
+ // fall through to base class
+ }
+ else if (message.GetMessage() == GUI_MSG_ITEM_SELECT)
+ {
+ SelectItem(message.GetParam1());
+ return true;
+ }
+ }
+ return CGUIBaseContainer::OnMessage(message);
+}
+
+void CGUIPanelContainer::OnLeft()
+{
+ bool wrapAround = m_controlLeft == GetID() || !(m_controlLeft || m_leftActions.size());
+ if (m_orientation == VERTICAL && MoveLeft(wrapAround))
+ return;
+ if (m_orientation == HORIZONTAL && MoveUp(wrapAround))
+ return;
+ CGUIControl::OnLeft();
+}
+
+void CGUIPanelContainer::OnRight()
+{
+ bool wrapAround = m_controlRight == GetID() || !(m_controlRight || m_rightActions.size());
+ if (m_orientation == VERTICAL && MoveRight(wrapAround))
+ return;
+ if (m_orientation == HORIZONTAL && MoveDown(wrapAround))
+ return;
+ return CGUIControl::OnRight();
+}
+
+void CGUIPanelContainer::OnUp()
+{
+ bool wrapAround = m_controlUp == GetID() || !(m_controlUp || m_upActions.size());
+ if (m_orientation == VERTICAL && MoveUp(wrapAround))
+ return;
+ if (m_orientation == HORIZONTAL && MoveLeft(wrapAround))
+ return;
+ CGUIControl::OnUp();
+}
+
+void CGUIPanelContainer::OnDown()
+{
+ bool wrapAround = m_controlDown == GetID() || !(m_controlDown || m_downActions.size());
+ if (m_orientation == VERTICAL && MoveDown(wrapAround))
+ return;
+ if (m_orientation == HORIZONTAL && MoveRight(wrapAround))
+ return;
+ return CGUIControl::OnDown();
+}
+
+bool CGUIPanelContainer::MoveDown(bool wrapAround)
+{
+ if (m_cursor + m_itemsPerRow < m_itemsPerPage * m_itemsPerRow && (m_offset + 1 + m_cursor / m_itemsPerRow) * m_itemsPerRow < (int)m_items.size())
+ { // move to last item if necessary
+ if ((m_offset + 1)*m_itemsPerRow + m_cursor >= (int)m_items.size())
+ SetCursor((int)m_items.size() - 1 - m_offset*m_itemsPerRow);
+ else
+ SetCursor(m_cursor + m_itemsPerRow);
+ }
+ else if ((m_offset + 1 + m_cursor / m_itemsPerRow) * m_itemsPerRow < (int)m_items.size())
+ { // we scroll to the next row, and move to last item if necessary
+ if ((m_offset + 1)*m_itemsPerRow + m_cursor >= (int)m_items.size())
+ SetCursor((int)m_items.size() - 1 - (m_offset + 1)*m_itemsPerRow);
+ ScrollToOffset(m_offset + 1);
+ }
+ else if (wrapAround)
+ { // move first item in list
+ SetCursor(m_cursor % m_itemsPerRow);
+ ScrollToOffset(0);
+ g_infoManager.SetContainerMoving(GetID(), 1);
+ }
+ else
+ return false;
+ return true;
+}
+
+bool CGUIPanelContainer::MoveUp(bool wrapAround)
+{
+ if (m_cursor >= m_itemsPerRow)
+ SetCursor(m_cursor - m_itemsPerRow);
+ else if (m_offset > 0)
+ ScrollToOffset(m_offset - 1);
+ else if (wrapAround)
+ { // move last item in list in this column
+ SetCursor((m_cursor % m_itemsPerRow) + (m_itemsPerPage - 1) * m_itemsPerRow);
+ int offset = max((int)GetRows() - m_itemsPerPage, 0);
+ // should check here whether cursor is actually allowed here, and reduce accordingly
+ if (offset * m_itemsPerRow + m_cursor >= (int)m_items.size())
+ SetCursor((int)m_items.size() - offset * m_itemsPerRow - 1);
+ ScrollToOffset(offset);
+ g_infoManager.SetContainerMoving(GetID(), -1);
+ }
+ else
+ return false;
+ return true;
+}
+
+bool CGUIPanelContainer::MoveLeft(bool wrapAround)
+{
+ int col = m_cursor % m_itemsPerRow;
+ if (col > 0)
+ SetCursor(m_cursor - 1);
+ else if (wrapAround)
+ { // wrap around
+ SetCursor(m_cursor + m_itemsPerRow - 1);
+ if (m_offset * m_itemsPerRow + m_cursor >= (int)m_items.size())
+ SetCursor((int)m_items.size() - m_offset * m_itemsPerRow);
+ }
+ else
+ return false;
+ return true;
+}
+
+bool CGUIPanelContainer::MoveRight(bool wrapAround)
+{
+ int col = m_cursor % m_itemsPerRow;
+ if (col + 1 < m_itemsPerRow && m_offset * m_itemsPerRow + m_cursor + 1 < (int)m_items.size())
+ SetCursor(m_cursor + 1);
+ else if (wrapAround) // move first item in row
+ SetCursor(m_cursor - col);
+ else
+ return false;
+ return true;
+}
+
+// scrolls the said amount
+void CGUIPanelContainer::Scroll(int amount)
+{
+ // increase or decrease the offset
+ int offset = m_offset + amount;
+ if (offset > ((int)GetRows() - m_itemsPerPage) * m_itemsPerRow)
+ {
+ offset = ((int)GetRows() - m_itemsPerPage) * m_itemsPerRow;
+ }
+ if (offset < 0) offset = 0;
+ ScrollToOffset(offset);
+}
+
+void CGUIPanelContainer::ValidateOffset()
+{ // first thing is we check the range of m_offset
+ if (!m_layout) return;
+ if (m_offset > (int)GetRows() - m_itemsPerPage)
+ {
+ m_offset = (int)GetRows() - m_itemsPerPage;
+ m_scrollOffset = m_offset * m_layout->Size(m_orientation);
+ }
+ if (m_offset < 0)
+ {
+ m_offset = 0;
+ m_scrollOffset = 0;
+ }
+}
+
+void CGUIPanelContainer::SetCursor(int cursor)
+{
+ // +1 to ensure we're OK if we have a half item
+ if (cursor > (m_itemsPerPage + 1)*m_itemsPerRow - 1) cursor = (m_itemsPerPage + 1)*m_itemsPerRow - 1;
+ if (cursor < 0) cursor = 0;
+ g_infoManager.SetContainerMoving(GetID(), cursor - m_cursor);
+ m_cursor = cursor;
+}
+
+void CGUIPanelContainer::CalculateLayout()
+{
+ GetCurrentLayouts();
+
+ if (!m_layout || !m_focusedLayout) return;
+ // calculate the number of items to display
+ if (m_orientation == HORIZONTAL)
+ {
+ m_itemsPerRow = (int)(m_height / m_layout->Size(VERTICAL));
+ m_itemsPerPage = (int)(m_width / m_layout->Size(HORIZONTAL));
+ }
+ else
+ {
+ m_itemsPerRow = (int)(m_width / m_layout->Size(HORIZONTAL));
+ m_itemsPerPage = (int)(m_height / m_layout->Size(VERTICAL));
+ }
+ if (m_itemsPerRow < 1) m_itemsPerRow = 1;
+ if (m_itemsPerPage < 1) m_itemsPerPage = 1;
+
+ // ensure that the scroll offset is a multiple of our size
+ m_scrollOffset = m_offset * m_layout->Size(m_orientation);
+}
+
+unsigned int CGUIPanelContainer::GetRows() const
+{
+ assert(m_itemsPerRow > 0);
+ return (m_items.size() + m_itemsPerRow - 1) / m_itemsPerRow;
+}
+
+float CGUIPanelContainer::AnalogScrollSpeed() const
+{
+ return 10.0f / m_itemsPerPage;
+}
+
+int CGUIPanelContainer::CorrectOffset(int offset, int cursor) const
+{
+ return offset * m_itemsPerRow + cursor;
+}
+
+bool CGUIPanelContainer::SelectItemFromPoint(const CPoint &point)
+{
+ if (!m_layout)
+ return false;
+
+ float sizeX = m_orientation == VERTICAL ? m_layout->Size(HORIZONTAL) : m_layout->Size(VERTICAL);
+ float sizeY = m_orientation == VERTICAL ? m_layout->Size(VERTICAL) : m_layout->Size(HORIZONTAL);
+
+ float posY = m_orientation == VERTICAL ? point.y : point.x;
+ for (int y = 0; y < m_itemsPerPage + 1; y++) // +1 to ensure if we have a half item we can select it
+ {
+ float posX = m_orientation == VERTICAL ? point.x : point.y;
+ for (int x = 0; x < m_itemsPerRow; x++)
+ {
+ int item = x + y * m_itemsPerRow;
+ if (posX < sizeX && posY < sizeY && item + m_offset < (int)m_items.size())
+ { // found
+ SetCursor(item);
+ return true;
+ }
+ posX -= sizeX;
+ }
+ posY -= sizeY;
+ }
+ return false;
+}
+
+bool CGUIPanelContainer::GetCondition(int condition, int data) const
+{ // probably only works vertically atm...
+ int row = m_cursor / m_itemsPerRow;
+ int col = m_cursor % m_itemsPerRow;
+ if (m_orientation == HORIZONTAL)
+ swap(row, col);
+ switch (condition)
+ {
+ case CONTAINER_ROW:
+ return (row == data);
+ case CONTAINER_COLUMN:
+ return (col == data);
+ default:
+ return CGUIBaseContainer::GetCondition(condition, data);
+ }
+}
+
+void CGUIPanelContainer::SelectItem(int item)
+{
+ // Check that m_offset is valid
+ ValidateOffset();
+ // only select an item if it's in a valid range
+ if (item >= 0 && item < (int)m_items.size())
+ {
+ // Select the item requested
+ if (item >= m_offset * m_itemsPerRow && item < (m_offset + m_itemsPerPage) * m_itemsPerRow)
+ { // the item is on the current page, so don't change it.
+ SetCursor(item - m_offset * m_itemsPerRow);
+ }
+ else if (item < m_offset * m_itemsPerRow)
+ { // item is on a previous page - make it the first item on the page
+ SetCursor(item % m_itemsPerRow);
+ ScrollToOffset((item - m_cursor) / m_itemsPerRow);
+ }
+ else // (item >= m_offset+m_itemsPerPage)
+ { // item is on a later page - make it the last row on the page
+ SetCursor(item % m_itemsPerRow + m_itemsPerRow * (m_itemsPerPage - 1));
+ ScrollToOffset((item - m_cursor) / m_itemsPerRow);
+ }
+ }
+}
+
+bool CGUIPanelContainer::HasPreviousPage() const
+{
+ return (m_offset > 0);
+}
+
+bool CGUIPanelContainer::HasNextPage() const
+{
+ return (m_offset != (int)GetRows() - m_itemsPerPage && (int)GetRows() > m_itemsPerPage);
+}
+
diff --git a/guilib/GUIPanelContainer.h b/guilib/GUIPanelContainer.h
new file mode 100644
index 0000000000..86ff4cdf38
--- /dev/null
+++ b/guilib/GUIPanelContainer.h
@@ -0,0 +1,69 @@
+/*!
+\file GUIPanelContainer.h
+\brief
+*/
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIBaseContainer.h"
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIPanelContainer : public CGUIBaseContainer
+{
+public:
+ CGUIPanelContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, int scrollTime, int preloadItems);
+ virtual ~CGUIPanelContainer(void);
+ virtual CGUIPanelContainer *Clone() const { return new CGUIPanelContainer(*this); };
+
+ virtual void Render();
+ virtual bool OnAction(const CAction &action);
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual void OnLeft();
+ virtual void OnRight();
+ virtual void OnUp();
+ virtual void OnDown();
+ virtual bool GetCondition(int condition, int data) const;
+protected:
+ virtual bool MoveUp(bool wrapAround);
+ virtual bool MoveDown(bool wrapAround);
+ virtual bool MoveLeft(bool wrapAround);
+ virtual bool MoveRight(bool wrapAround);
+ virtual void Scroll(int amount);
+ float AnalogScrollSpeed() const;
+ virtual void ValidateOffset();
+ virtual void CalculateLayout();
+ unsigned int GetRows() const;
+ virtual int CorrectOffset(int offset, int cursor) const;
+ virtual bool SelectItemFromPoint(const CPoint &point);
+ void SetCursor(int cursor);
+ virtual void SelectItem(int item);
+ virtual bool HasPreviousPage() const;
+ virtual bool HasNextPage() const;
+
+ int m_itemsPerRow;
+};
+
diff --git a/guilib/GUIProgressControl.cpp b/guilib/GUIProgressControl.cpp
new file mode 100644
index 0000000000..b491a06747
--- /dev/null
+++ b/guilib/GUIProgressControl.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIProgressControl.h"
+#include "utils/GUIInfoManager.h"
+
+CGUIProgressControl::CGUIProgressControl(int parentID, int controlID,
+ float posX, float posY, float width,
+ float height, const CTextureInfo& backGroundTexture,
+ const CTextureInfo& leftTexture,
+ const CTextureInfo& midTexture,
+ const CTextureInfo& rightTexture,
+ const CTextureInfo& overlayTexture, float min, float max,
+ bool reveal)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+ , m_guiBackground(posX, posY, width, height, backGroundTexture)
+ , m_guiLeft(posX, posY, width, height, leftTexture)
+ , m_guiMid(posX, posY, width, height, midTexture)
+ , m_guiRight(posX, posY, width, height, rightTexture)
+ , m_guiOverlay(posX, posY, width, height, overlayTexture)
+{
+ m_RangeMin = min;
+ m_RangeMax = max;
+ m_fPercent = 0;
+ m_iInfoCode = 0;
+ ControlType = GUICONTROL_PROGRESS;
+ m_bReveal = reveal;
+}
+
+CGUIProgressControl::~CGUIProgressControl(void)
+{
+}
+
+void CGUIProgressControl::SetPosition(float posX, float posY)
+{
+ // everything is positioned based on the background image position
+ CGUIControl::SetPosition(posX, posY);
+ m_guiBackground.SetPosition(posX, posY);
+}
+
+void CGUIProgressControl::Render()
+{
+ if (!IsDisabled())
+ {
+ if (m_iInfoCode )
+ {
+ m_fPercent = (float)g_infoManager.GetInt(m_iInfoCode);
+ if ((m_RangeMax - m_RangeMin)> 0 && (m_RangeMax != 100 && m_RangeMin != 0) )
+ {
+ if (m_fPercent > m_RangeMax)
+ m_fPercent = m_RangeMax;
+ if (m_fPercent < m_RangeMin)
+ m_fPercent = m_RangeMin;
+ m_fPercent = ((100*(m_fPercent - m_RangeMin)) / (m_RangeMax - m_RangeMin));
+ }
+ }
+ if (m_fPercent < 0.0f) m_fPercent = 0.0f;
+ if (m_fPercent > 100.0f) m_fPercent = 100.0f;
+
+ float fScaleX, fScaleY;
+ if (m_width == 0)
+ m_width = m_guiBackground.GetTextureWidth();
+ if (m_height == 0)
+ m_height = m_guiBackground.GetTextureHeight();
+ fScaleY = m_height / m_guiBackground.GetTextureHeight();
+ fScaleX = m_width / m_guiBackground.GetTextureWidth();
+
+ m_guiBackground.SetHeight(m_height);
+ m_guiBackground.SetWidth(m_width);
+ m_guiBackground.Render();
+
+ float fWidth = m_fPercent;
+
+ float posX = m_guiBackground.GetXPosition();
+ float posY = m_guiBackground.GetYPosition();
+
+ if (m_guiLeft.GetFileName().IsEmpty() && m_guiRight.GetFileName().IsEmpty())
+ { // rendering without left and right image - fill the mid image completely
+ float width = m_fPercent * m_width * 0.01f;
+ if (m_fPercent && width > 1)
+ {
+ float offset = fabs(fScaleY * 0.5f * (m_guiMid.GetTextureHeight() - m_guiBackground.GetTextureHeight()));
+ if (offset > 0) // Center texture to the background if necessary
+ m_guiMid.SetPosition(posX, posY + offset);
+ else
+ m_guiMid.SetPosition(posX, posY);
+ m_guiMid.SetHeight(fScaleY * m_guiMid.GetTextureHeight());
+ if (m_bReveal)
+ {
+ m_guiMid.SetWidth(m_width);
+ g_graphicsContext.SetClipRegion(posX, posY+offset, width, fScaleY * m_guiMid.GetTextureHeight());
+ m_guiMid.Render();
+ g_graphicsContext.RestoreClipRegion();
+ }
+ else
+ {
+ m_guiMid.SetWidth(width);
+ m_guiMid.Render();
+ }
+ posX += fWidth * fScaleX;
+ }
+ }
+ else
+ {
+
+ float fWidth = m_fPercent;
+ float fFullWidth = m_guiBackground.GetTextureWidth() - m_guiLeft.GetTextureWidth() - m_guiRight.GetTextureWidth();
+ fWidth /= 100.0f;
+ fWidth *= fFullWidth;
+
+ float offset = fabs(fScaleY * 0.5f * (m_guiLeft.GetTextureHeight() - m_guiBackground.GetTextureHeight()));
+ if (offset > 0) // Center texture to the background if necessary
+ m_guiLeft.SetPosition(posX, posY + offset);
+ else
+ m_guiLeft.SetPosition(posX, posY);
+ m_guiLeft.SetHeight(fScaleY * m_guiLeft.GetTextureHeight());
+ m_guiLeft.SetWidth(fScaleX * m_guiLeft.GetTextureWidth());
+ m_guiLeft.Render();
+
+ posX += fScaleX * m_guiLeft.GetTextureWidth();
+ if (m_fPercent && (int)(fScaleX * fWidth) > 1)
+ {
+ float offset = fabs(fScaleY * 0.5f * (m_guiMid.GetTextureHeight() - m_guiBackground.GetTextureHeight()));
+ if (offset > 0) // Center texture to the background if necessary
+ m_guiMid.SetPosition(posX, posY + offset);
+ else
+ m_guiMid.SetPosition(posX, posY);
+ m_guiMid.SetHeight(fScaleY * m_guiMid.GetTextureHeight());
+ if (m_bReveal)
+ {
+ m_guiMid.SetWidth(fScaleX * fFullWidth);
+ g_graphicsContext.SetClipRegion(posX, posY+offset, fScaleX * fWidth, fScaleY * m_guiMid.GetTextureHeight());
+ m_guiMid.Render();
+ g_graphicsContext.RestoreClipRegion();
+ }
+ else
+ {
+ m_guiMid.SetWidth(fScaleX * fWidth);
+ m_guiMid.Render();
+ }
+ posX += fWidth * fScaleX;
+ }
+
+ offset = fabs(fScaleY * 0.5f * (m_guiRight.GetTextureHeight() - m_guiBackground.GetTextureHeight()));
+ if (offset > 0) // Center texture to the background if necessary
+ m_guiRight.SetPosition(posX, posY + offset);
+ else
+ m_guiRight.SetPosition(posX, posY);
+ m_guiRight.SetHeight(fScaleY * m_guiRight.GetTextureHeight());
+ m_guiRight.SetWidth(fScaleX * m_guiRight.GetTextureWidth());
+ m_guiRight.Render();
+ }
+ float offset = fabs(fScaleY * 0.5f * (m_guiOverlay.GetTextureHeight() - m_guiBackground.GetTextureHeight()));
+ if (offset > 0) // Center texture to the background if necessary
+ m_guiOverlay.SetPosition(m_guiBackground.GetXPosition(), m_guiBackground.GetYPosition() + offset);
+ else
+ m_guiOverlay.SetPosition(m_guiBackground.GetXPosition(), m_guiBackground.GetYPosition());
+ m_guiOverlay.SetHeight(fScaleY * m_guiOverlay.GetTextureHeight());
+ m_guiOverlay.SetWidth(fScaleX * m_guiOverlay.GetTextureWidth());
+ m_guiOverlay.Render();
+ }
+ CGUIControl::Render();
+}
+
+
+bool CGUIProgressControl::CanFocus() const
+{
+ return false;
+}
+
+
+bool CGUIProgressControl::OnMessage(CGUIMessage& message)
+{
+ return CGUIControl::OnMessage(message);
+}
+
+void CGUIProgressControl::SetPercentage(float fPercent)
+{
+ m_fPercent = fPercent;
+}
+
+float CGUIProgressControl::GetPercentage() const
+{
+ return m_fPercent;
+}
+void CGUIProgressControl::FreeResources()
+{
+ CGUIControl::FreeResources();
+ m_guiBackground.FreeResources();
+ m_guiMid.FreeResources();
+ m_guiRight.FreeResources();
+ m_guiLeft.FreeResources();
+ m_guiOverlay.FreeResources();
+}
+
+void CGUIProgressControl::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+ m_guiBackground.DynamicResourceAlloc(bOnOff);
+ m_guiMid.DynamicResourceAlloc(bOnOff);
+ m_guiRight.DynamicResourceAlloc(bOnOff);
+ m_guiLeft.DynamicResourceAlloc(bOnOff);
+ m_guiOverlay.DynamicResourceAlloc(bOnOff);
+}
+
+void CGUIProgressControl::AllocResources()
+{
+ CGUIControl::AllocResources();
+ m_guiBackground.AllocResources();
+ m_guiMid.AllocResources();
+ m_guiRight.AllocResources();
+ m_guiLeft.AllocResources();
+ m_guiOverlay.AllocResources();
+
+ m_guiBackground.SetHeight(25);
+ m_guiRight.SetHeight(20);
+ m_guiLeft.SetHeight(20);
+ m_guiMid.SetHeight(20);
+ m_guiOverlay.SetHeight(20);
+}
+
+void CGUIProgressControl::SetInfo(int iInfo)
+{
+ m_iInfoCode = iInfo;
+}
+
+void CGUIProgressControl::UpdateColors()
+{
+ CGUIControl::UpdateColors();
+ m_guiBackground.SetDiffuseColor(m_diffuseColor);
+ m_guiRight.SetDiffuseColor(m_diffuseColor);
+ m_guiLeft.SetDiffuseColor(m_diffuseColor);
+ m_guiMid.SetDiffuseColor(m_diffuseColor);
+ m_guiOverlay.SetDiffuseColor(m_diffuseColor);
+}
+
+CStdString CGUIProgressControl::GetDescription() const
+{
+ CStdString percent;
+ percent.Format("%2.f", m_fPercent);
+ return percent;
+}
diff --git a/guilib/GUIProgressControl.h b/guilib/GUIProgressControl.h
new file mode 100644
index 0000000000..25bf9e4c5d
--- /dev/null
+++ b/guilib/GUIProgressControl.h
@@ -0,0 +1,77 @@
+/*!
+\file GUIProgressControl.h
+\brief
+*/
+
+#ifndef GUILIB_GUIPROGRESSCONTROL_H
+#define GUILIB_GUIPROGRESSCONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUITexture.h"
+#include "GUIControl.h"
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIProgressControl :
+ public CGUIControl
+{
+public:
+ CGUIProgressControl(int parentID, int controlID, float posX, float posY,
+ float width, float height, const CTextureInfo& backGroundTexture,
+ const CTextureInfo& leftTexture, const CTextureInfo& midTexture,
+ const CTextureInfo& rightTexture, const CTextureInfo& overlayTexture,
+ float min, float max, bool reveal=false);
+ virtual ~CGUIProgressControl(void);
+ virtual CGUIProgressControl *Clone() const { return new CGUIProgressControl(*this); };
+
+ virtual void Render();
+ virtual bool CanFocus() const;
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual void SetPosition(float posX, float posY);
+ void SetPercentage(float fPercent);
+ void SetInfo(int iInfo);
+ int GetInfo() const {return m_iInfoCode;};
+
+ float GetPercentage() const;
+ CStdString GetDescription() const;
+protected:
+ virtual void UpdateColors();
+ CGUITexture m_guiBackground;
+ CGUITexture m_guiLeft;
+ CGUITexture m_guiMid;
+ CGUITexture m_guiRight;
+ CGUITexture m_guiOverlay;
+ float m_RangeMin;
+ float m_RangeMax;
+ int m_iInfoCode;
+ float m_fPercent;
+ bool m_bReveal;
+};
+#endif
diff --git a/guilib/GUIRSSControl.cpp b/guilib/GUIRSSControl.cpp
new file mode 100644
index 0000000000..9f30312c98
--- /dev/null
+++ b/guilib/GUIRSSControl.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIRSSControl.h"
+#include "GUIWindowManager.h"
+#include "GUISettings.h"
+#include "utils/CriticalSection.h"
+#include "utils/SingleLock.h"
+#include "utils/RssReader.h"
+#include "StringUtils.h"
+
+using namespace std;
+
+CGUIRSSControl::CGUIRSSControl(int parentID, int controlID, float posX, float posY, float width, float height, const CLabelInfo& labelInfo, const CGUIInfoColor &channelColor, const CGUIInfoColor &headlineColor, CStdString& strRSSTags, int scrollSpeed)
+: CGUIControl(parentID, controlID, posX, posY, width, height),
+ m_scrollInfo(0,0,scrollSpeed,"")
+{
+ m_label = labelInfo;
+ m_headlineColor = headlineColor;
+ m_channelColor = channelColor;
+
+ m_strRSSTags = strRSSTags;
+
+ m_pReader = NULL;
+ ControlType = GUICONTROL_RSS;
+
+ if (g_guiSettings.GetBool("lookandfeel.rssfeedsrtl"))
+ {
+ m_scrollInfo.SetSpeed(-60);
+ }
+}
+
+CGUIRSSControl::CGUIRSSControl(const CGUIRSSControl &from)
+: CGUIControl(from),m_scrollInfo(from.m_scrollInfo)
+{
+ m_label = from.m_label;
+ m_headlineColor = from.m_headlineColor;
+ m_channelColor = from.m_channelColor;
+ m_strRSSTags = from.m_strRSSTags;
+ m_pReader = NULL;
+ ControlType = GUICONTROL_RSS;
+}
+
+CGUIRSSControl::~CGUIRSSControl(void)
+{
+ CSingleLock lock(m_criticalSection);
+ if (m_pReader)
+ m_pReader->SetObserver(NULL);
+ m_pReader = NULL;
+}
+
+void CGUIRSSControl::SetUrls(const vector<string> &vecUrl)
+{
+ m_vecUrls = vecUrl;
+}
+
+void CGUIRSSControl::SetIntervals(const vector<int>& vecIntervals)
+{
+ m_vecIntervals = vecIntervals;
+}
+
+void CGUIRSSControl::UpdateColors()
+{
+ m_label.UpdateColors();
+ m_headlineColor.Update();
+ m_channelColor.Update();
+ CGUIControl::UpdateColors();
+}
+
+void CGUIRSSControl::Render()
+{
+ // only render the control if they are enabled
+ if (g_guiSettings.GetBool("lookandfeel.enablerssfeeds") && g_rssManager.IsActive())
+ {
+ CSingleLock lock(m_criticalSection);
+ // Create RSS background/worker thread if needed
+ if (m_pReader == NULL)
+ {
+ if (g_rssManager.GetReader(GetID(), GetParentID(), this, m_pReader))
+ m_scrollInfo.characterPos = m_pReader->m_SavedScrollPos;
+ else
+ {
+ if (m_strRSSTags != "")
+ {
+ CStdStringArray vecSplitTags;
+
+ StringUtils::SplitString(m_strRSSTags, ",", vecSplitTags);
+
+ for (unsigned int i = 0;i < vecSplitTags.size();i++)
+ m_pReader->AddTag(vecSplitTags[i]);
+ }
+ // use half the width of the control as spacing between feeds, and double this between feed sets
+ float spaceWidth = (m_label.font) ? m_label.font->GetCharWidth(L' ') : 15;
+ m_pReader->Create(this, m_vecUrls, m_vecIntervals, (int)(0.5f*GetWidth() / spaceWidth) + 1);
+ }
+ }
+
+ if (m_label.font)
+ {
+ vecColors colors;
+ colors.push_back(m_label.textColor);
+ colors.push_back(m_headlineColor);
+ colors.push_back(m_channelColor);
+ m_label.font->DrawScrollingText(m_posX, m_posY, colors, m_label.shadowColor, m_feed, 0, m_width, m_scrollInfo);
+ }
+
+ if (m_pReader)
+ {
+ m_pReader->CheckForUpdates();
+ m_pReader->m_SavedScrollPos = m_scrollInfo.characterPos;
+ }
+ }
+ CGUIControl::Render();
+}
+
+void CGUIRSSControl::OnFeedUpdate(const vecText &feed)
+{
+ CSingleLock lock(m_criticalSection);
+ m_feed = feed;
+}
+
+void CGUIRSSControl::OnFeedRelease()
+{
+ m_pReader = NULL;
+}
+
+
diff --git a/guilib/GUIRSSControl.h b/guilib/GUIRSSControl.h
new file mode 100644
index 0000000000..8d3aa4e0db
--- /dev/null
+++ b/guilib/GUIRSSControl.h
@@ -0,0 +1,87 @@
+/*!
+\file GUIRSSControl.h
+\brief
+*/
+
+#ifndef GUILIB_GUIRSSControl_H
+#define GUILIB_GUIRSSControl_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+
+typedef uint32_t character_t;
+typedef uint32_t color_t;
+typedef std::vector<character_t> vecText;
+typedef std::vector<color_t> vecColors;
+
+class CRssReader;
+
+class IRssObserver
+{
+public:
+ virtual void OnFeedUpdate(const vecText &feed) = 0;
+ virtual void OnFeedRelease() = 0;
+ virtual ~IRssObserver() {}
+};
+
+/*!
+\ingroup controls
+\brief
+*/
+class CGUIRSSControl : public CGUIControl, public IRssObserver
+{
+public:
+ CGUIRSSControl(int parentID, int controlID, float posX, float posY, float width, float height, const CLabelInfo& labelInfo, const CGUIInfoColor &channelColor, const CGUIInfoColor &headlineColor, CStdString& strRSSTags, int scrollSpeed);
+ CGUIRSSControl(const CGUIRSSControl &from);
+ virtual ~CGUIRSSControl(void);
+ virtual CGUIRSSControl *Clone() const { return new CGUIRSSControl(*this); };
+
+ virtual void Render();
+ virtual void OnFeedUpdate(const vecText &feed);
+ virtual void OnFeedRelease();
+ virtual bool CanFocus() const { return false; };
+
+ void SetIntervals(const std::vector<int>& vecIntervals);
+ void SetUrls(const std::vector<std::string>& vecUrl);
+
+protected:
+ virtual void UpdateColors();
+
+ CCriticalSection m_criticalSection;
+
+ CRssReader* m_pReader;
+ vecText m_feed;
+
+ CStdString m_strRSSTags;
+
+ CLabelInfo m_label;
+ CGUIInfoColor m_channelColor;
+ CGUIInfoColor m_headlineColor;
+
+ std::vector<std::string> m_vecUrls;
+ std::vector<int> m_vecIntervals;
+ CScrollInfo m_scrollInfo;
+};
+#endif
diff --git a/guilib/GUIRadioButtonControl.cpp b/guilib/GUIRadioButtonControl.cpp
new file mode 100644
index 0000000000..43111eb571
--- /dev/null
+++ b/guilib/GUIRadioButtonControl.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIRadioButtonControl.h"
+#include "utils/GUIInfoManager.h"
+#include "GUIFontManager.h"
+#include "Key.h"
+
+CGUIRadioButtonControl::CGUIRadioButtonControl(int parentID, int controlID, float posX, float posY, float width, float height,
+ const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus,
+ const CLabelInfo& labelInfo,
+ const CTextureInfo& radioOn, const CTextureInfo& radioOff)
+ : CGUIButtonControl(parentID, controlID, posX, posY, width, height, textureFocus, textureNoFocus, labelInfo)
+ , m_imgRadioOn(posX, posY, 16, 16, radioOn)
+ , m_imgRadioOff(posX, posY, 16, 16, radioOff)
+{
+ m_radioPosX = 0;
+ m_radioPosY = 0;
+ m_toggleSelect = 0;
+ m_imgRadioOn.SetAspectRatio(CAspectRatio::AR_KEEP);\
+ m_imgRadioOff.SetAspectRatio(CAspectRatio::AR_KEEP);
+ ControlType = GUICONTROL_RADIO;
+}
+
+CGUIRadioButtonControl::~CGUIRadioButtonControl(void)
+{}
+
+
+void CGUIRadioButtonControl::Render()
+{
+ CGUIButtonControl::Render();
+
+ // ask our infoManager whether we are selected or not...
+ if (m_toggleSelect)
+ m_bSelected = g_infoManager.GetBool(m_toggleSelect, m_parentID);
+
+ if ( IsSelected() && !IsDisabled() )
+ m_imgRadioOn.Render();
+ else
+ m_imgRadioOff.Render();
+}
+
+bool CGUIRadioButtonControl::OnAction(const CAction &action)
+{
+ if (action.id == ACTION_SELECT_ITEM)
+ {
+ m_bSelected = !m_bSelected;
+ }
+ return CGUIButtonControl::OnAction(action);
+}
+
+bool CGUIRadioButtonControl::OnMessage(CGUIMessage& message)
+{
+ return CGUIButtonControl::OnMessage(message);
+}
+
+void CGUIRadioButtonControl::AllocResources()
+{
+ CGUIButtonControl::AllocResources();
+ m_imgRadioOn.AllocResources();
+ m_imgRadioOff.AllocResources();
+
+ SetPosition(m_posX, m_posY);
+}
+
+void CGUIRadioButtonControl::FreeResources()
+{
+ CGUIButtonControl::FreeResources();
+ m_imgRadioOn.FreeResources();
+ m_imgRadioOff.FreeResources();
+}
+
+void CGUIRadioButtonControl::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+ m_imgRadioOn.DynamicResourceAlloc(bOnOff);
+ m_imgRadioOff.DynamicResourceAlloc(bOnOff);
+}
+
+void CGUIRadioButtonControl::SetPosition(float posX, float posY)
+{
+ CGUIButtonControl::SetPosition(posX, posY);
+ float radioPosX = m_radioPosX ? m_posX + m_radioPosX : (m_posX + m_width - 8) - m_imgRadioOn.GetWidth();
+ float radioPosY = m_radioPosY ? m_posY + m_radioPosY : m_posY + (m_height - m_imgRadioOn.GetHeight()) / 2;
+ m_imgRadioOn.SetPosition(radioPosX, radioPosY);
+ m_imgRadioOff.SetPosition(radioPosX, radioPosY);
+}
+
+void CGUIRadioButtonControl::SetRadioDimensions(float posX, float posY, float width, float height)
+{
+ m_radioPosX = posX;
+ m_radioPosY = posY;
+ if (width)
+ {
+ m_imgRadioOn.SetWidth(width);
+ m_imgRadioOff.SetWidth(width);
+ }
+ if (height)
+ {
+ m_imgRadioOn.SetHeight(height);
+ m_imgRadioOff.SetHeight(height);
+ }
+ SetPosition(GetXPosition(), GetYPosition());
+}
+
+void CGUIRadioButtonControl::SetWidth(float width)
+{
+ CGUIButtonControl::SetWidth(width);
+ SetPosition(GetXPosition(), GetYPosition());
+}
+
+void CGUIRadioButtonControl::SetHeight(float height)
+{
+ CGUIButtonControl::SetHeight(height);
+ SetPosition(GetXPosition(), GetYPosition());
+}
+
+CStdString CGUIRadioButtonControl::GetDescription() const
+{
+ CStdString strLabel = CGUIButtonControl::GetDescription();
+ if (m_bSelected)
+ strLabel += " (*)";
+ else
+ strLabel += " ( )";
+ return strLabel;
+}
+
+void CGUIRadioButtonControl::UpdateColors()
+{
+ CGUIButtonControl::UpdateColors();
+ m_imgRadioOn.SetDiffuseColor(m_diffuseColor);
+ m_imgRadioOff.SetDiffuseColor(m_diffuseColor);
+}
+
diff --git a/guilib/GUIRadioButtonControl.h b/guilib/GUIRadioButtonControl.h
new file mode 100644
index 0000000000..80dba57873
--- /dev/null
+++ b/guilib/GUIRadioButtonControl.h
@@ -0,0 +1,68 @@
+/*!
+\file GUIRadioButtonControl.h
+\brief
+*/
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIButtonControl.h"
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIRadioButtonControl :
+ public CGUIButtonControl
+{
+public:
+ CGUIRadioButtonControl(int parentID, int controlID,
+ float posX, float posY, float width, float height,
+ const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus,
+ const CLabelInfo& labelInfo,
+ const CTextureInfo& radioOn, const CTextureInfo& radioOff);
+
+ virtual ~CGUIRadioButtonControl(void);
+ virtual CGUIRadioButtonControl *Clone() const { return new CGUIRadioButtonControl(*this); };
+
+ virtual void Render();
+ virtual bool OnAction(const CAction &action) ;
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual void SetPosition(float posX, float posY);
+ virtual void SetWidth(float width);
+ virtual void SetHeight(float height);
+ virtual CStdString GetDescription() const;
+ void SetRadioDimensions(float posX, float posY, float width, float height);
+ void SetToggleSelect(int toggleSelect) { m_toggleSelect = toggleSelect; };
+ bool IsSelected() const { return m_bSelected; };
+protected:
+ virtual void UpdateColors();
+ CGUITexture m_imgRadioOn;
+ CGUITexture m_imgRadioOff;
+ float m_radioPosX;
+ float m_radioPosY;
+ int m_toggleSelect;
+};
diff --git a/guilib/GUIResizeControl.cpp b/guilib/GUIResizeControl.cpp
new file mode 100644
index 0000000000..03d8b2106e
--- /dev/null
+++ b/guilib/GUIResizeControl.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIResizeControl.h"
+#include "GUIWindowManager.h"
+#include "MouseStat.h"
+#include "Key.h"
+
+// time to reset accelerated cursors (digital movement)
+#define MOVE_TIME_OUT 500L
+
+CGUIResizeControl::CGUIResizeControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+ , m_imgFocus(posX, posY, width, height, textureFocus)
+ , m_imgNoFocus(posX, posY, width, height, textureNoFocus)
+{
+ m_dwFrameCounter = 0;
+ m_dwLastMoveTime = 0;
+ m_fSpeed = 1.0;
+ m_fAnalogSpeed = 2.0f; // TODO: implement correct analog speed
+ m_fAcceleration = 0.2f; // TODO: implement correct computation of acceleration
+ m_fMaxSpeed = 10.0; // TODO: implement correct computation of maxspeed
+ ControlType = GUICONTROL_RESIZE;
+ SetLimits(0, 0, 720, 576); // defaults
+}
+
+CGUIResizeControl::~CGUIResizeControl(void)
+{}
+
+void CGUIResizeControl::Render()
+{
+ if (m_bInvalidated)
+ {
+ m_imgFocus.SetWidth(m_width);
+ m_imgFocus.SetHeight(m_height);
+
+ m_imgNoFocus.SetWidth(m_width);
+ m_imgNoFocus.SetHeight(m_height);
+ }
+ if (HasFocus())
+ {
+ DWORD dwAlphaCounter = m_dwFrameCounter + 2;
+ DWORD dwAlphaChannel;
+ if ((dwAlphaCounter % 128) >= 64)
+ dwAlphaChannel = dwAlphaCounter % 64;
+ else
+ dwAlphaChannel = 63 - (dwAlphaCounter % 64);
+
+ dwAlphaChannel += 192;
+ SetAlpha( (unsigned char)dwAlphaChannel );
+ m_imgFocus.SetVisible(true);
+ m_imgNoFocus.SetVisible(false);
+ m_dwFrameCounter++;
+ }
+ else
+ {
+ SetAlpha(0xff);
+ m_imgFocus.SetVisible(false);
+ m_imgNoFocus.SetVisible(true);
+ }
+ // render both so the visibility settings cause the frame counter to resetcorrectly
+ m_imgFocus.Render();
+ m_imgNoFocus.Render();
+ CGUIControl::Render();
+}
+
+bool CGUIResizeControl::OnAction(const CAction &action)
+{
+ if (action.id == ACTION_SELECT_ITEM)
+ {
+ // button selected - send message to parent
+ CGUIMessage message(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(message);
+ return true;
+ }
+ if (action.id == ACTION_ANALOG_MOVE)
+ {
+ Resize(m_fAnalogSpeed*action.amount1, -m_fAnalogSpeed*action.amount2);
+ return true;
+ }
+ return CGUIControl::OnAction(action);
+}
+
+void CGUIResizeControl::OnUp()
+{
+ UpdateSpeed(DIRECTION_UP);
+ Resize(0, -m_fSpeed);
+}
+
+void CGUIResizeControl::OnDown()
+{
+ UpdateSpeed(DIRECTION_DOWN);
+ Resize(0, m_fSpeed);
+}
+
+void CGUIResizeControl::OnLeft()
+{
+ UpdateSpeed(DIRECTION_LEFT);
+ Resize(-m_fSpeed, 0);
+}
+
+void CGUIResizeControl::OnRight()
+{
+ UpdateSpeed(DIRECTION_RIGHT);
+ Resize(m_fSpeed, 0);
+}
+
+bool CGUIResizeControl::OnMouseDrag(const CPoint &offset, const CPoint &point)
+{
+ g_Mouse.SetState(MOUSE_STATE_DRAG);
+ g_Mouse.SetExclusiveAccess(GetID(), GetParentID(), point);
+ Resize(offset.x, offset.y);
+ return true;
+}
+
+bool CGUIResizeControl::OnMouseClick(int button, const CPoint &point)
+{
+ if (button != MOUSE_LEFT_BUTTON) return false;
+ g_Mouse.EndExclusiveAccess(GetID(), GetParentID());
+ return true;
+}
+
+void CGUIResizeControl::UpdateSpeed(int nDirection)
+{
+ if (timeGetTime() - m_dwLastMoveTime > MOVE_TIME_OUT)
+ {
+ m_fSpeed = 1;
+ m_nDirection = DIRECTION_NONE;
+ }
+ m_dwLastMoveTime = timeGetTime();
+ if (nDirection == m_nDirection)
+ { // accelerate
+ m_fSpeed += m_fAcceleration;
+ if (m_fSpeed > m_fMaxSpeed) m_fSpeed = m_fMaxSpeed;
+ }
+ else
+ { // reset direction and speed
+ m_fSpeed = 1;
+ m_nDirection = nDirection;
+ }
+}
+
+void CGUIResizeControl::AllocResources()
+{
+ CGUIControl::AllocResources();
+ m_dwFrameCounter = 0;
+ m_imgFocus.AllocResources();
+ m_imgNoFocus.AllocResources();
+ m_width = m_imgFocus.GetWidth();
+ m_height = m_imgFocus.GetHeight();
+}
+
+void CGUIResizeControl::FreeResources()
+{
+ CGUIControl::FreeResources();
+ m_imgFocus.FreeResources();
+ m_imgNoFocus.FreeResources();
+}
+
+void CGUIResizeControl::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+ m_imgFocus.DynamicResourceAlloc(bOnOff);
+ m_imgNoFocus.DynamicResourceAlloc(bOnOff);
+}
+
+void CGUIResizeControl::Resize(float x, float y)
+{
+ float width = m_width + x;
+ float height = m_height + y;
+ // check if we are within the bounds
+ if (width < m_x1) width = m_x1;
+ if (height < m_y1) height = m_y1;
+ if (width > m_x2) width = m_x2;
+ if (height > m_y2) height = m_y2;
+ // ok, now set the default size of the resize control
+ SetWidth(width);
+ SetHeight(height);
+}
+
+void CGUIResizeControl::SetPosition(float posX, float posY)
+{
+ CGUIControl::SetPosition(posX, posY);
+ m_imgFocus.SetPosition(posX, posY);
+ m_imgNoFocus.SetPosition(posX, posY);
+}
+
+void CGUIResizeControl::SetAlpha(unsigned char alpha)
+{
+ m_imgFocus.SetAlpha(alpha);
+ m_imgNoFocus.SetAlpha(alpha);
+}
+
+void CGUIResizeControl::UpdateColors()
+{
+ CGUIControl::UpdateColors();
+ m_imgFocus.SetDiffuseColor(m_diffuseColor);
+ m_imgNoFocus.SetDiffuseColor(m_diffuseColor);
+}
+
+void CGUIResizeControl::SetLimits(float x1, float y1, float x2, float y2)
+{
+ m_x1 = x1;
+ m_y1 = y1;
+ m_x2 = x2;
+ m_y2 = y2;
+}
diff --git a/guilib/GUIResizeControl.h b/guilib/GUIResizeControl.h
new file mode 100644
index 0000000000..452bd72aaf
--- /dev/null
+++ b/guilib/GUIResizeControl.h
@@ -0,0 +1,85 @@
+/*!
+\file GUIRESIZEControl.h
+\brief
+*/
+
+#ifndef GUILIB_GUIRESIZECONTROL_H
+#define GUILIB_GUIRESIZECONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUITexture.h"
+#include "GUIControl.h"
+
+#define DIRECTION_NONE 0
+#define DIRECTION_UP 1
+#define DIRECTION_DOWN 2
+#define DIRECTION_LEFT 3
+#define DIRECTION_RIGHT 4
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIResizeControl : public CGUIControl
+{
+public:
+ CGUIResizeControl(int parentID, int controlID,
+ float posX, float posY, float width, float height,
+ const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus);
+
+ virtual ~CGUIResizeControl(void);
+ virtual CGUIResizeControl *Clone() const { return new CGUIResizeControl(*this); };
+
+ virtual void Render();
+ virtual bool OnAction(const CAction &action);
+ virtual void OnUp();
+ virtual void OnDown();
+ virtual void OnLeft();
+ virtual void OnRight();
+ virtual bool OnMouseDrag(const CPoint &offset, const CPoint &point);
+ virtual bool OnMouseClick(int button, const CPoint &point);
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual void SetPosition(float posX, float posY);
+ void SetLimits(float x1, float y1, float x2, float y2);
+
+protected:
+ virtual void UpdateColors();
+ void SetAlpha(unsigned char alpha);
+ void UpdateSpeed(int nDirection);
+ void Resize(float x, float y);
+ CGUITexture m_imgFocus;
+ CGUITexture m_imgNoFocus;
+ DWORD m_dwFrameCounter;
+ DWORD m_dwLastMoveTime;
+ int m_nDirection;
+ float m_fSpeed;
+ float m_fAnalogSpeed;
+ float m_fMaxSpeed;
+ float m_fAcceleration;
+ float m_x1, m_x2, m_y1, m_y2;
+};
+#endif
diff --git a/guilib/GUIScrollBarControl.cpp b/guilib/GUIScrollBarControl.cpp
new file mode 100644
index 0000000000..9cd7125367
--- /dev/null
+++ b/guilib/GUIScrollBarControl.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIScrollBarControl.h"
+#include "MouseStat.h"
+#include "Key.h"
+
+#define MIN_NIB_SIZE 4.0f
+
+CGUIScrollBar::CGUIScrollBar(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& backGroundTexture, const CTextureInfo& barTexture, const CTextureInfo& barTextureFocus, const CTextureInfo& nibTexture, const CTextureInfo& nibTextureFocus, ORIENTATION orientation, bool showOnePage)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+ , m_guiBackground(posX, posY, width, height, backGroundTexture)
+ , m_guiBarNoFocus(posX, posY, width, height, barTexture)
+ , m_guiBarFocus(posX, posY, width, height, barTextureFocus)
+ , m_guiNibNoFocus(posX, posY, width, height, nibTexture)
+ , m_guiNibFocus(posX, posY, width, height, nibTextureFocus)
+{
+ m_guiNibNoFocus.SetAspectRatio(CAspectRatio::AR_CENTER);
+ m_guiNibFocus.SetAspectRatio(CAspectRatio::AR_CENTER);
+ m_numItems = 100;
+ m_offset = 0;
+ m_pageSize = 10;
+ ControlType = GUICONTROL_SCROLLBAR;
+ m_orientation = orientation;
+ m_showOnePage = showOnePage;
+}
+
+CGUIScrollBar::~CGUIScrollBar(void)
+{
+}
+
+
+void CGUIScrollBar::Render()
+{
+ if (m_bInvalidated)
+ UpdateBarSize();
+
+ m_guiBackground.Render();
+ if (m_bHasFocus)
+ {
+ m_guiBarFocus.Render();
+ m_guiNibFocus.Render();
+ }
+ else
+ {
+ m_guiBarNoFocus.Render();
+ m_guiNibNoFocus.Render();
+ }
+
+ CGUIControl::Render();
+}
+
+bool CGUIScrollBar::OnMessage(CGUIMessage& message)
+{
+ switch (message.GetMessage())
+ {
+ case GUI_MSG_ITEM_SELECT:
+ SetValue(message.GetParam1());
+ return true;
+ case GUI_MSG_LABEL_RESET:
+ SetRange(message.GetParam1(), message.GetParam2());
+ return true;
+ case GUI_MSG_PAGE_UP:
+ Move(-1);
+ return true;
+ case GUI_MSG_PAGE_DOWN:
+ Move(1);
+ return true;
+ }
+ return CGUIControl::OnMessage(message);
+}
+
+bool CGUIScrollBar::OnAction(const CAction &action)
+{
+ switch ( action.id )
+ {
+ case ACTION_MOVE_LEFT:
+ if (m_orientation == HORIZONTAL)
+ {
+ Move( -1);
+ return true;
+ }
+ break;
+
+ case ACTION_MOVE_RIGHT:
+ if (m_orientation == HORIZONTAL)
+ {
+ Move(1);
+ return true;
+ }
+ break;
+ case ACTION_MOVE_UP:
+ if (m_orientation == VERTICAL)
+ {
+ Move(-1);
+ return true;
+ }
+ break;
+
+ case ACTION_MOVE_DOWN:
+ if (m_orientation == VERTICAL)
+ {
+ Move(1);
+ return true;
+ }
+ break;
+ }
+ return CGUIControl::OnAction(action);
+}
+
+void CGUIScrollBar::Move(int numSteps)
+{
+ m_offset += numSteps * m_pageSize;
+ if (m_offset > m_numItems - m_pageSize) m_offset = m_numItems - m_pageSize;
+ if (m_offset < 0) m_offset = 0;
+ CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetParentID(), GetID(), GUI_MSG_PAGE_CHANGE, m_offset);
+ SendWindowMessage(message);
+ SetInvalid();
+}
+
+void CGUIScrollBar::SetRange(int pageSize, int numItems)
+{
+ m_pageSize = pageSize;
+ m_numItems = numItems;
+ m_offset = 0;
+ SetInvalid();
+}
+
+void CGUIScrollBar::SetValue(int value)
+{
+ m_offset = value;
+ SetInvalid();
+}
+
+void CGUIScrollBar::FreeResources()
+{
+ CGUIControl::FreeResources();
+ m_guiBackground.FreeResources();
+ m_guiBarNoFocus.FreeResources();
+ m_guiBarFocus.FreeResources();
+ m_guiNibNoFocus.FreeResources();
+ m_guiNibFocus.FreeResources();
+}
+
+void CGUIScrollBar::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+ m_guiBackground.DynamicResourceAlloc(bOnOff);
+ m_guiBarNoFocus.DynamicResourceAlloc(bOnOff);
+ m_guiBarFocus.DynamicResourceAlloc(bOnOff);
+ m_guiNibNoFocus.DynamicResourceAlloc(bOnOff);
+ m_guiNibFocus.DynamicResourceAlloc(bOnOff);
+}
+
+void CGUIScrollBar::AllocResources()
+{
+ CGUIControl::AllocResources();
+ m_guiBackground.AllocResources();
+ m_guiBarNoFocus.AllocResources();
+ m_guiBarFocus.AllocResources();
+ m_guiNibNoFocus.AllocResources();
+ m_guiNibFocus.AllocResources();
+}
+
+void CGUIScrollBar::UpdateBarSize()
+{
+ // scale our textures to suit
+ if (m_orientation == VERTICAL)
+ {
+ // calculate the height to display the nib at
+ float percent = (float)m_pageSize / m_numItems;
+ float nibSize = GetHeight() * percent;
+ if (nibSize < m_guiNibFocus.GetTextureHeight() + 2 * MIN_NIB_SIZE) nibSize = m_guiNibFocus.GetTextureHeight() + 2 * MIN_NIB_SIZE;
+ if (nibSize > GetHeight()) nibSize = GetHeight();
+
+ m_guiBarNoFocus.SetHeight(nibSize);
+ m_guiBarFocus.SetHeight(nibSize);
+ m_guiNibNoFocus.SetHeight(nibSize);
+ m_guiNibFocus.SetHeight(nibSize);
+ // nibSize may be altered by the border size of the nib (and bar).
+ nibSize = std::max(m_guiBarFocus.GetHeight(), m_guiNibFocus.GetHeight());
+
+ // and the position
+ percent = (m_numItems == m_pageSize) ? 0 : (float)m_offset / (m_numItems - m_pageSize);
+ float nibPos = (GetHeight() - nibSize) * percent;
+ if (nibPos < 0) nibPos = 0;
+ if (nibPos > GetHeight() - nibSize) nibPos = GetHeight() - nibSize;
+ m_guiBarNoFocus.SetPosition(GetXPosition(), GetYPosition() + nibPos);
+ m_guiBarFocus.SetPosition(GetXPosition(), GetYPosition() + nibPos);
+ m_guiNibNoFocus.SetPosition(GetXPosition(), GetYPosition() + nibPos);
+ m_guiNibFocus.SetPosition(GetXPosition(), GetYPosition() + nibPos);
+ }
+ else
+ {
+ // calculate the height to display the nib at
+ float percent = (float)m_pageSize / m_numItems;
+ float nibSize = GetWidth() * percent + 0.5f;
+ if (nibSize < m_guiNibFocus.GetTextureWidth() + 2 * MIN_NIB_SIZE) nibSize = m_guiNibFocus.GetTextureWidth() + 2 * MIN_NIB_SIZE;
+ if (nibSize > GetWidth()) nibSize = GetWidth();
+
+ m_guiBarNoFocus.SetWidth(nibSize);
+ m_guiBarFocus.SetWidth(nibSize);
+ m_guiNibNoFocus.SetWidth(nibSize);
+ m_guiNibFocus.SetWidth(nibSize);
+
+ // and the position
+ percent = (float)m_offset / (m_numItems - m_pageSize);
+ float nibPos = (GetWidth() - nibSize) * percent;
+ if (nibPos < 0) nibPos = 0;
+ if (nibPos > GetWidth() - nibSize) nibPos = GetWidth() - nibSize;
+ m_guiBarNoFocus.SetPosition(GetXPosition() + nibPos, GetYPosition());
+ m_guiBarFocus.SetPosition(GetXPosition() + nibPos, GetYPosition());
+ m_guiNibNoFocus.SetPosition(GetXPosition() + nibPos, GetYPosition());
+ m_guiNibFocus.SetPosition(GetXPosition() + nibPos, GetYPosition());
+ }
+}
+
+bool CGUIScrollBar::HitTest(const CPoint &point) const
+{
+ if (m_guiBackground.HitTest(point)) return true;
+ if (m_guiBarNoFocus.HitTest(point)) return true;
+ return false;
+}
+
+void CGUIScrollBar::SetFromPosition(const CPoint &point)
+{
+ float fPercent;
+ if (m_orientation == VERTICAL)
+ fPercent = (point.y - m_guiBackground.GetYPosition() - 0.5f*m_guiBarFocus.GetHeight()) / m_guiBackground.GetHeight();
+ else
+ fPercent = (point.x - m_guiBackground.GetXPosition() - 0.5f*m_guiBarFocus.GetWidth()) / m_guiBackground.GetWidth();
+ if (fPercent < 0) fPercent = 0;
+ if (fPercent > 1) fPercent = 1;
+ m_offset = (int)(floor(fPercent * m_numItems + 0.5f));
+ CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetParentID(), GetID(), GUI_MSG_PAGE_CHANGE, m_offset);
+ SendWindowMessage(message);
+ SetInvalid();
+}
+
+bool CGUIScrollBar::OnMouseClick(int button, const CPoint &point)
+{
+ g_Mouse.SetState(MOUSE_STATE_CLICK);
+ // turn off any exclusive access, if it's on...
+ g_Mouse.EndExclusiveAccess(GetID(), GetParentID());
+ if (m_guiBackground.HitTest(point))
+ { // set the position
+ SetFromPosition(point);
+ return true;
+ }
+ return false;
+}
+
+bool CGUIScrollBar::OnMouseDrag(const CPoint &offset, const CPoint &point)
+{
+ g_Mouse.SetState(MOUSE_STATE_DRAG);
+ // get exclusive access to the mouse
+ g_Mouse.SetExclusiveAccess(GetID(), GetParentID(), point);
+ // get the position of the mouse
+ SetFromPosition(point);
+ return true;
+}
+
+bool CGUIScrollBar::OnMouseWheel(char wheel, const CPoint &point)
+{
+ Move(-wheel);
+ return true;
+}
+
+CStdString CGUIScrollBar::GetDescription() const
+{
+ CStdString description;
+ description.Format("%i/%i", m_offset, m_numItems);
+ return description;
+}
+
+void CGUIScrollBar::UpdateColors()
+{
+ CGUIControl::UpdateColors();
+ m_guiBackground.SetDiffuseColor(m_diffuseColor);
+ m_guiBarNoFocus.SetDiffuseColor(m_diffuseColor);
+ m_guiBarFocus.SetDiffuseColor(m_diffuseColor);
+ m_guiNibNoFocus.SetDiffuseColor(m_diffuseColor);
+ m_guiNibFocus.SetDiffuseColor(m_diffuseColor);
+}
+
+bool CGUIScrollBar::IsVisible() const
+{
+ // page controls can be optionally disabled if the number of pages is 1
+ if (m_numItems <= m_pageSize && !m_showOnePage)
+ return false;
+ return CGUIControl::IsVisible();
+}
diff --git a/guilib/GUIScrollBarControl.h b/guilib/GUIScrollBarControl.h
new file mode 100644
index 0000000000..9e98f96492
--- /dev/null
+++ b/guilib/GUIScrollBarControl.h
@@ -0,0 +1,86 @@
+/*!
+\file GUIScrollBar.h
+\brief
+*/
+
+#ifndef GUILIB_GUISCROLLBAR_H
+#define GUILIB_GUISCROLLBAR_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUITexture.h"
+#include "GUIControl.h"
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIScrollBar :
+ public CGUIControl
+{
+public:
+ CGUIScrollBar(int parentID, int controlID, float posX, float posY,
+ float width, float height,
+ const CTextureInfo& backGroundTexture,
+ const CTextureInfo& barTexture, const CTextureInfo& barTextureFocus,
+ const CTextureInfo& nibTexture, const CTextureInfo& nibTextureFocus,
+ ORIENTATION orientation, bool showOnePage);
+ virtual ~CGUIScrollBar(void);
+ virtual CGUIScrollBar *Clone() const { return new CGUIScrollBar(*this); };
+
+ virtual void Render();
+ virtual bool OnAction(const CAction &action);
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual void SetRange(int pageSize, int numItems);
+ virtual bool OnMessage(CGUIMessage& message);
+ void SetValue(int value);
+ int GetValue() const;
+ virtual bool HitTest(const CPoint &point) const;
+ virtual bool OnMouseClick(int button, const CPoint &point);
+ virtual bool OnMouseDrag(const CPoint &offset, const CPoint &point);
+ virtual bool OnMouseWheel(char wheel, const CPoint &point);
+ virtual CStdString GetDescription() const;
+ virtual bool IsVisible() const;
+protected:
+ virtual void UpdateColors();
+ void UpdateBarSize();
+ virtual void Move(int iNumSteps);
+ virtual void SetFromPosition(const CPoint &point);
+
+ CGUITexture m_guiBackground;
+ CGUITexture m_guiBarNoFocus;
+ CGUITexture m_guiBarFocus;
+ CGUITexture m_guiNibNoFocus;
+ CGUITexture m_guiNibFocus;
+
+ int m_numItems;
+ int m_pageSize;
+ int m_offset;
+
+ bool m_showOnePage;
+ ORIENTATION m_orientation;
+};
+#endif
diff --git a/guilib/GUISelectButtonControl.cpp b/guilib/GUISelectButtonControl.cpp
new file mode 100644
index 0000000000..a51d30e6d9
--- /dev/null
+++ b/guilib/GUISelectButtonControl.cpp
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUISelectButtonControl.h"
+#include "GUIWindowManager.h"
+#include "utils/CharsetConverter.h"
+#include "MouseStat.h"
+#include "Key.h"
+
+CGUISelectButtonControl::CGUISelectButtonControl(int parentID, int controlID,
+ float posX, float posY,
+ float width, float height,
+ const CTextureInfo& buttonFocus,
+ const CTextureInfo& button,
+ const CLabelInfo& labelInfo,
+ const CTextureInfo& selectBackground,
+ const CTextureInfo& selectArrowLeft,
+ const CTextureInfo& selectArrowLeftFocus,
+ const CTextureInfo& selectArrowRight,
+ const CTextureInfo& selectArrowRightFocus
+ )
+ : CGUIButtonControl(parentID, controlID, posX, posY, width, height, buttonFocus, button, labelInfo)
+ , m_imgBackground(posX, posY, width, height, selectBackground)
+ , m_imgLeft(posX, posY, 16, 16, selectArrowLeft)
+ , m_imgLeftFocus(posX, posY, 16, 16, selectArrowLeftFocus)
+ , m_imgRight(posX, posY, 16, 16, selectArrowRight)
+ , m_imgRightFocus(posX, posY, 16, 16, selectArrowRightFocus)
+{
+ m_bShowSelect = false;
+ m_iCurrentItem = -1;
+ m_iDefaultItem = -1;
+ m_iStartFrame = 0;
+ m_bLeftSelected = false;
+ m_bRightSelected = false;
+ m_bMovedLeft = false;
+ m_bMovedRight = false;
+ m_dwTicks = 0;
+ ControlType = GUICONTROL_SELECTBUTTON;
+}
+
+CGUISelectButtonControl::~CGUISelectButtonControl(void)
+{}
+
+void CGUISelectButtonControl::Render()
+{
+ if (m_bInvalidated)
+ {
+ m_imgBackground.SetWidth(m_width);
+ m_imgBackground.SetHeight(m_height);
+ }
+ // Are we in selection mode
+ if (m_bShowSelect)
+ {
+ // render background, left and right arrow
+ m_imgBackground.Render();
+
+ color_t textColor = m_label.textColor;
+
+ // User has moved left...
+ if (m_bMovedLeft)
+ {
+ m_iStartFrame++;
+ if (m_iStartFrame >= 10)
+ {
+ m_iStartFrame = 0;
+ m_bMovedLeft = false;
+ }
+ // If we are moving left
+ // render item text as disabled
+ textColor = m_label.disabledColor;
+ }
+
+ // Render arrow
+ if (m_bLeftSelected || m_bMovedLeft)
+ m_imgLeftFocus.Render();
+ else
+ m_imgLeft.Render();
+
+ // User has moved right...
+ if (m_bMovedRight)
+ {
+ m_iStartFrame++;
+ if (m_iStartFrame >= 10)
+ {
+ m_iStartFrame = 0;
+ m_bMovedRight = false;
+ }
+ // If we are moving right
+ // render item text as disabled
+ textColor = m_label.disabledColor;
+ }
+
+ // Render arrow
+ if (m_bRightSelected || m_bMovedRight)
+ m_imgRightFocus.Render();
+ else
+ m_imgRight.Render();
+
+ // Render text if a current item is available
+ if (m_iCurrentItem >= 0 && (unsigned)m_iCurrentItem < m_vecItems.size())
+ {
+ m_textLayout.Update(m_vecItems[m_iCurrentItem]);
+ uint32_t align = m_label.align | XBFONT_CENTER_X;
+ float fPosY = m_posY + m_label.offsetY;
+ if (m_label.align & XBFONT_CENTER_Y)
+ fPosY = m_posY + m_imgBackground.GetHeight()*0.5f;
+ m_textLayout.Render(m_posX + GetWidth()*0.5f, fPosY, 0, textColor, m_label.shadowColor, align, m_label.width);
+ }
+
+ // Select current item, if user doesn't
+ // move left or right for 1.5 sec.
+ DWORD dwTicksSpan = timeGetTime() - m_dwTicks;
+ if (dwTicksSpan > 1500)
+ {
+ // User hasn't moved disable selection mode...
+ m_bShowSelect = false;
+
+ // ...and send a thread message.
+ // (Sending a message with SendMessage
+ // can result in a GPF.)
+ CGUIMessage message(GUI_MSG_CLICKED, GetID(), GetParentID() );
+ m_gWindowManager.SendThreadMessage(message);
+ }
+ } // if (m_bShowSelect)
+ else
+ {
+ // No, render a normal button
+ CGUIButtonControl::Render();
+ }
+ CGUIControl::Render();
+}
+
+bool CGUISelectButtonControl::OnMessage(CGUIMessage& message)
+{
+ if ( message.GetControlId() == GetID() )
+ {
+ if (message.GetMessage() == GUI_MSG_LABEL_ADD)
+ {
+ if (m_vecItems.size() <= 0)
+ {
+ m_iCurrentItem = 0;
+ m_iDefaultItem = 0;
+ }
+ m_vecItems.push_back(message.GetLabel());
+ return true;
+ }
+ else if (message.GetMessage() == GUI_MSG_LABEL_RESET)
+ {
+ m_vecItems.erase(m_vecItems.begin(), m_vecItems.end());
+ m_iCurrentItem = -1;
+ m_iDefaultItem = -1;
+ return true;
+ }
+ else if (message.GetMessage() == GUI_MSG_ITEM_SELECTED)
+ {
+ message.SetParam1(m_iCurrentItem);
+ if (m_iCurrentItem >= 0 && m_iCurrentItem < (int)m_vecItems.size())
+ message.SetLabel(m_vecItems[m_iCurrentItem]);
+ return true;
+ }
+ else if (message.GetMessage() == GUI_MSG_ITEM_SELECT)
+ {
+ m_iDefaultItem = m_iCurrentItem = message.GetParam1();
+ return true;
+ }
+ }
+
+ return CGUIButtonControl::OnMessage(message);
+}
+
+bool CGUISelectButtonControl::OnAction(const CAction &action)
+{
+ if (!m_bShowSelect)
+ {
+ if (action.id == ACTION_SELECT_ITEM)
+ {
+ // Enter selection mode
+ m_bShowSelect = true;
+
+ // Start timer, if user doesn't select an item
+ // or moves left/right. The control will
+ // automatically select the current item.
+ m_dwTicks = timeGetTime();
+ return true;
+ }
+ else
+ return CGUIButtonControl::OnAction(action);
+ }
+ else
+ {
+ if (action.id == ACTION_SELECT_ITEM)
+ {
+ // User has selected an item, disable selection mode...
+ m_bShowSelect = false;
+
+ // ...and send a message.
+ CGUIMessage message(GUI_MSG_CLICKED, GetID(), GetParentID() );
+ SendWindowMessage(message);
+ return true;
+ }
+ if (action.id == ACTION_MOVE_UP || action.id == ACTION_MOVE_DOWN )
+ {
+ // Disable selection mode when moving up or down
+ m_bShowSelect = false;
+ m_iCurrentItem = m_iDefaultItem;
+ }
+ // call the base class
+ return CGUIButtonControl::OnAction(action);
+ }
+}
+
+void CGUISelectButtonControl::FreeResources()
+{
+ CGUIButtonControl::FreeResources();
+
+ m_imgBackground.FreeResources();
+
+ m_imgLeft.FreeResources();
+ m_imgLeftFocus.FreeResources();
+
+ m_imgRight.FreeResources();
+ m_imgRightFocus.FreeResources();
+
+ m_bShowSelect = false;
+}
+
+void CGUISelectButtonControl::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+
+ m_imgBackground.DynamicResourceAlloc(bOnOff);
+
+ m_imgLeft.DynamicResourceAlloc(bOnOff);
+ m_imgLeftFocus.DynamicResourceAlloc(bOnOff);
+
+ m_imgRight.DynamicResourceAlloc(bOnOff);
+ m_imgRightFocus.DynamicResourceAlloc(bOnOff);
+}
+
+void CGUISelectButtonControl::AllocResources()
+{
+ CGUIButtonControl::AllocResources();
+
+ m_imgBackground.AllocResources();
+
+ m_imgLeft.AllocResources();
+ m_imgLeftFocus.AllocResources();
+
+ m_imgRight.AllocResources();
+ m_imgRightFocus.AllocResources();
+
+ // Position right arrow
+ float posX = (m_posX + m_width - 8) - 16;
+ float posY = m_posY + (m_height - 16) / 2;
+ m_imgRight.SetPosition(posX, posY);
+ m_imgRightFocus.SetPosition(posX, posY);
+
+ // Position left arrow
+ posX = m_posX + 8;
+ m_imgLeft.SetPosition(posX, posY);
+ m_imgLeftFocus.SetPosition(posX, posY);
+}
+
+void CGUISelectButtonControl::OnLeft()
+{
+ if (m_bShowSelect)
+ {
+ // Set for visual feedback
+ m_bMovedLeft = true;
+ m_iStartFrame = 0;
+
+ // Reset timer for automatically selecting
+ // the current item.
+ m_dwTicks = timeGetTime();
+
+ // Switch to previous item
+ if (m_vecItems.size() > 0)
+ {
+ m_iCurrentItem--;
+ if (m_iCurrentItem < 0)
+ m_iCurrentItem = (int)m_vecItems.size() - 1;
+ }
+ }
+ else
+ { // use the base class
+ CGUIButtonControl::OnLeft();
+ }
+}
+
+void CGUISelectButtonControl::OnRight()
+{
+ if (m_bShowSelect)
+ {
+ // Set for visual feedback
+ m_bMovedRight = true;
+ m_iStartFrame = 0;
+
+ // Reset timer for automatically selecting
+ // the current item.
+ m_dwTicks = timeGetTime();
+
+ // Switch to next item
+ if (m_vecItems.size() > 0)
+ {
+ m_iCurrentItem++;
+ if (m_iCurrentItem >= (int)m_vecItems.size())
+ m_iCurrentItem = 0;
+ }
+ }
+ else
+ { // use the base class
+ CGUIButtonControl::OnRight();
+ }
+}
+
+bool CGUISelectButtonControl::OnMouseOver(const CPoint &point)
+{
+ bool ret = CGUIControl::OnMouseOver(point);
+ m_bLeftSelected = false;
+ m_bRightSelected = false;
+ if (m_imgLeft.HitTest(point))
+ { // highlight the left control, but don't start moving until we have clicked
+ m_bLeftSelected = true;
+ }
+ if (m_imgRight.HitTest(point))
+ { // highlight the right control, but don't start moving until we have clicked
+ m_bRightSelected = true;
+ }
+ // reset ticks
+ m_dwTicks = timeGetTime();
+ return ret;
+}
+
+bool CGUISelectButtonControl::OnMouseClick(int button, const CPoint &point)
+{ // only left click handled
+ if (button != MOUSE_LEFT_BUTTON) return false;
+ if (m_bShowSelect && m_imgLeft.HitTest(point))
+ { // move left
+ OnLeft();
+ }
+ else if (m_bShowSelect && m_imgRight.HitTest(point))
+ { // move right
+ OnRight();
+ }
+ else
+ { // normal select
+ CGUIButtonControl::OnMouseClick(button, point);
+ }
+ return true;
+}
+
+bool CGUISelectButtonControl::OnMouseWheel(char wheel, const CPoint &point)
+{
+ if (wheel > 0)
+ OnLeft();
+ else
+ OnRight();
+ return true;
+}
+
+void CGUISelectButtonControl::SetPosition(float posX, float posY)
+{
+ float leftOffX = m_imgLeft.GetXPosition() - m_posX;
+ float leftOffY = m_imgLeft.GetYPosition() - m_posY;
+ float rightOffX = m_imgRight.GetXPosition() - m_posX;
+ float rightOffY = m_imgRight.GetYPosition() - m_posY;
+ float backOffX = m_imgBackground.GetXPosition() - m_posX;
+ float backOffY = m_imgBackground.GetYPosition() - m_posY;
+ CGUIButtonControl::SetPosition(posX, posY);
+ m_imgLeft.SetPosition(posX + leftOffX, posY + leftOffY);
+ m_imgLeftFocus.SetPosition(posX + leftOffX, posY + leftOffY);
+ m_imgRight.SetPosition(posX + rightOffX, posY + rightOffY);
+ m_imgRightFocus.SetPosition(posX + rightOffX, posY + rightOffY);
+ m_imgBackground.SetPosition(posX + backOffX, posY + backOffY);
+}
+
+void CGUISelectButtonControl::UpdateColors()
+{
+ CGUIButtonControl::UpdateColors();
+ m_imgLeft.SetDiffuseColor(m_diffuseColor);
+ m_imgLeftFocus.SetDiffuseColor(m_diffuseColor);
+ m_imgRight.SetDiffuseColor(m_diffuseColor);
+ m_imgRightFocus.SetDiffuseColor(m_diffuseColor);
+ m_imgBackground.SetDiffuseColor(m_diffuseColor);
+}
+
diff --git a/guilib/GUISelectButtonControl.h b/guilib/GUISelectButtonControl.h
new file mode 100644
index 0000000000..8ca08418f7
--- /dev/null
+++ b/guilib/GUISelectButtonControl.h
@@ -0,0 +1,134 @@
+/*!
+\file GUISelectButtonControl.h
+\brief
+*/
+
+#ifndef GUILIB_GUIWINDOWSELECTCONTROL_H
+#define GUILIB_GUIWINDOWSELECTCONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIButtonControl.h"
+
+/*!
+ \ingroup controls
+ \brief Button with multi selection choice.
+
+ Behaves like a normal button control, but when pressing,
+ it can show multiple strings. The user can choose one by
+ moving left or right. \n
+ \n
+ Messages the button reactes on: \n
+
+ - GUI_MSG_LABEL_ADD \n
+ Add a label to the control. Use CGUIMessage::SetLabel
+ to set the label text.
+ - GUI_MSG_LABEL_RESET \n
+ Remove all labels from the control.
+ - GUI_MSG_ITEM_SELECTED \n
+ After sending this message the CGUIMessage::GetParam1
+ contains the selected label as an integer.
+ \note The order of the items depends on the order they have been added to
+ the control using GUI_MSG_LABEL_ADD.
+ - GUI_MSG_ITEM_SELECT \n
+ Send this message with CGUIMessage::SetParam1() set to the label
+ to be selected. \n
+ \n
+ Example entry to define a select button in a window or as reference control: \n
+ \verbatim
+ <control>
+ <description>default select button</description
+ <type>selectbutton</type>
+ <id>6</id>
+ <posX>60</posX>
+ <posY>192</posY>
+ <width>130</width>
+ <height>32</height>
+ <label>132</label>
+ <font>font13</font>
+ <textureFocus>button-focus.png</textureFocus>
+ <textureNoFocus>button-nofocus.jpg</textureNoFocus>
+ <texturebg>button-focus.png</texturebg>
+ <textureLeft>scroll-left.png</textureLeft>
+ <textureRight>scroll-right.png</textureRight>
+ <font>font13</font>
+ <textcolor>ffffffff</textcolor>
+ <colordiffuse>ffffffff</colordiffuse>
+ <disabledcolor>60ffffff</disabledcolor>
+ <onleft>50</onleft>
+ <onright>50</onright>
+ <onup>3</onup>
+ <ondown>7</ondown>
+ </control>
+ \endverbatim
+
+ \sa CGUIMessage
+ */
+class CGUISelectButtonControl : public CGUIButtonControl
+{
+public:
+ CGUISelectButtonControl(int parentID, int controlID,
+ float posX, float posY,
+ float width, float height,
+ const CTextureInfo& buttonFocus, const CTextureInfo& button,
+ const CLabelInfo& labelInfo,
+ const CTextureInfo& selectBackground,
+ const CTextureInfo& selectArrowLeft, const CTextureInfo& selectArrowLeftFocus,
+ const CTextureInfo& selectArrowRight, const CTextureInfo& selectArrowRightFocus);
+ virtual ~CGUISelectButtonControl(void);
+ virtual CGUISelectButtonControl *Clone() const { return new CGUISelectButtonControl(*this); };
+
+ virtual void Render();
+ virtual bool OnAction(const CAction &action) ;
+ virtual void OnLeft();
+ virtual void OnRight();
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual bool OnMouseOver(const CPoint &point);
+ virtual bool OnMouseClick(int button, const CPoint &point);
+ virtual bool OnMouseWheel(char wheel, const CPoint &point);
+
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual void SetPosition(float posX, float posY);
+
+protected:
+ virtual void UpdateColors();
+ bool m_bShowSelect;
+ CGUITexture m_imgBackground;
+ CGUITexture m_imgLeft;
+ CGUITexture m_imgLeftFocus;
+ CGUITexture m_imgRight;
+ CGUITexture m_imgRightFocus;
+ std::vector<std::string> m_vecItems;
+ int m_iCurrentItem;
+ int m_iDefaultItem;
+ int m_iStartFrame;
+ bool m_bLeftSelected;
+ bool m_bRightSelected;
+ bool m_bMovedLeft;
+ bool m_bMovedRight;
+ DWORD m_dwTicks;
+};
+#endif
diff --git a/guilib/GUISettingsSliderControl.cpp b/guilib/GUISettingsSliderControl.cpp
new file mode 100644
index 0000000000..c6f0e3206a
--- /dev/null
+++ b/guilib/GUISettingsSliderControl.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUISettingsSliderControl.h"
+
+CGUISettingsSliderControl::CGUISettingsSliderControl(int parentID, int controlID, float posX, float posY, float width, float height, float sliderWidth, float sliderHeight, const CTextureInfo &textureFocus, const CTextureInfo &textureNoFocus, const CTextureInfo& backGroundTexture, const CTextureInfo& nibTexture, const CTextureInfo& nibTextureFocus, const CLabelInfo &labelInfo, int iType)
+ : CGUISliderControl(parentID, controlID, posX, posY, sliderWidth, sliderHeight, backGroundTexture, nibTexture,nibTextureFocus, iType)
+ , m_buttonControl(parentID, controlID, posX, posY, width, height, textureFocus, textureNoFocus, labelInfo)
+ , m_textLayout(labelInfo.font, false)
+{
+ ControlType = GUICONTROL_SETTINGS_SLIDER;
+}
+
+CGUISettingsSliderControl::~CGUISettingsSliderControl(void)
+{
+}
+
+
+void CGUISettingsSliderControl::Render()
+{
+ if (IsDisabled()) return ;
+
+ // make sure the button has focus if it should have...
+ m_buttonControl.SetFocus(HasFocus());
+ m_buttonControl.SetPulseOnSelect(m_pulseOnSelect);
+ m_buttonControl.Render();
+ CGUISliderControl::Render();
+
+ // now render our text
+ m_textLayout.Update(CGUISliderControl::GetDescription());
+
+ float posX = m_posX - m_buttonControl.GetLabelInfo().offsetX;
+ float posY = GetYPosition() + GetHeight() * 0.5f;
+ if (HasFocus() && m_buttonControl.GetLabelInfo().focusedColor)
+ m_textLayout.Render(posX, posY, 0, m_buttonControl.GetLabelInfo().focusedColor, m_buttonControl.GetLabelInfo().shadowColor, XBFONT_CENTER_Y | XBFONT_RIGHT, 0);
+ else
+ m_textLayout.Render(posX, posY, 0, m_buttonControl.GetLabelInfo().textColor, m_buttonControl.GetLabelInfo().shadowColor, XBFONT_CENTER_Y | XBFONT_RIGHT, 0);
+}
+
+bool CGUISettingsSliderControl::OnAction(const CAction &action)
+{
+ return CGUISliderControl::OnAction(action);
+}
+
+void CGUISettingsSliderControl::FreeResources()
+{
+ CGUISliderControl::FreeResources();
+ m_buttonControl.FreeResources();
+}
+
+void CGUISettingsSliderControl::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUISliderControl::DynamicResourceAlloc(bOnOff);
+ m_buttonControl.DynamicResourceAlloc(bOnOff);
+}
+
+void CGUISettingsSliderControl::AllocResources()
+{
+ CGUISliderControl::AllocResources();
+ m_buttonControl.AllocResources();
+}
+
+void CGUISettingsSliderControl::SetPosition(float posX, float posY)
+{
+ m_buttonControl.SetPosition(posX, posY);
+ float sliderPosX = posX + m_buttonControl.GetWidth() - m_width - m_buttonControl.GetLabelInfo().offsetX;
+ float sliderPosY = posY + (m_buttonControl.GetHeight() - m_height) * 0.5f;
+ CGUISliderControl::SetPosition(sliderPosX, sliderPosY);
+}
+
+void CGUISettingsSliderControl::SetWidth(float width)
+{
+ m_buttonControl.SetWidth(width);
+ SetPosition(GetXPosition(), GetYPosition());
+}
+
+void CGUISettingsSliderControl::SetHeight(float height)
+{
+ m_buttonControl.SetHeight(height);
+ SetPosition(GetXPosition(), GetYPosition());
+}
+
+void CGUISettingsSliderControl::SetEnabled(bool bEnable)
+{
+ CGUISliderControl::SetEnabled(bEnable);
+ m_buttonControl.SetEnabled(bEnable);
+}
+
+CStdString CGUISettingsSliderControl::GetDescription() const
+{
+ return m_buttonControl.GetDescription() + " " + CGUISliderControl::GetDescription();
+}
+
+void CGUISettingsSliderControl::UpdateColors()
+{
+ m_buttonControl.UpdateColors();
+ CGUISliderControl::UpdateColors();
+}
diff --git a/guilib/GUISettingsSliderControl.h b/guilib/GUISettingsSliderControl.h
new file mode 100644
index 0000000000..eb9a5a6f6e
--- /dev/null
+++ b/guilib/GUISettingsSliderControl.h
@@ -0,0 +1,73 @@
+/*!
+\file GUISliderControl.h
+\brief
+*/
+
+#ifndef GUILIB_GUISettingsSliderCONTROL_H
+#define GUILIB_GUISettingsSliderCONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUISliderControl.h"
+#include "GUIButtonControl.h"
+
+#define SPIN_CONTROL_TYPE_INT 1
+#define SPIN_CONTROL_TYPE_FLOAT 2
+#define SPIN_CONTROL_TYPE_TEXT 3
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUISettingsSliderControl :
+ public CGUISliderControl
+{
+public:
+ CGUISettingsSliderControl(int parentID, int controlID, float posX, float posY, float width, float height, float sliderWidth, float sliderHeight, const CTextureInfo &textureFocus, const CTextureInfo &textureNoFocus, const CTextureInfo& backGroundTexture, const CTextureInfo& nibTexture, const CTextureInfo& nibTextureFocus, const CLabelInfo &labelInfo, int iType);
+ virtual ~CGUISettingsSliderControl(void);
+ virtual CGUISettingsSliderControl *Clone() const { return new CGUISettingsSliderControl(*this); };
+
+ virtual void Render();
+ virtual bool OnAction(const CAction &action);
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual void SetPosition(float posX, float posY);
+ virtual float GetWidth() const { return m_buttonControl.GetWidth();};
+ virtual void SetWidth(float width);
+ virtual float GetHeight() const { return m_buttonControl.GetHeight();};
+ virtual void SetHeight(float height);
+ virtual void SetEnabled(bool bEnable);
+
+ void SetText(const std::string &label) {m_buttonControl.SetLabel(label);};
+ virtual float GetXPosition() const { return m_buttonControl.GetXPosition();};
+ virtual float GetYPosition() const { return m_buttonControl.GetYPosition();};
+ virtual CStdString GetDescription() const;
+ virtual bool HitTest(const CPoint &point) const { return m_buttonControl.HitTest(point); };
+protected:
+ virtual void UpdateColors();
+ CGUIButtonControl m_buttonControl;
+ CGUITextLayout m_textLayout;
+};
+#endif
diff --git a/guilib/GUISliderControl.cpp b/guilib/GUISliderControl.cpp
new file mode 100644
index 0000000000..582a195c84
--- /dev/null
+++ b/guilib/GUISliderControl.cpp
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUISliderControl.h"
+#include "utils/GUIInfoManager.h"
+#include "MouseStat.h"
+#include "Key.h"
+
+CGUISliderControl::CGUISliderControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& backGroundTexture, const CTextureInfo& nibTexture, const CTextureInfo& nibTextureFocus, int iType)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+ , m_guiBackground(posX, posY, width, height, backGroundTexture)
+ , m_guiMid(posX, posY, width, height, nibTexture)
+ , m_guiMidFocus(posX, posY, width, height, nibTextureFocus)
+{
+ m_iType = iType;
+ m_iPercent = 0;
+ m_iStart = 0;
+ m_iEnd = 100;
+ m_fStart = 0.0f;
+ m_fEnd = 1.0f;
+ m_fInterval = 0.1f;
+ m_iValue = 0;
+ m_fValue = 0.0;
+ ControlType = GUICONTROL_SLIDER;
+ m_iInfoCode = 0;
+}
+
+CGUISliderControl::~CGUISliderControl(void)
+{
+}
+
+void CGUISliderControl::Render()
+{
+ m_guiBackground.SetPosition( m_posX, m_posY );
+ float proportion = 0;
+ if (!IsDisabled())
+ {
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_FLOAT:
+ if (m_iInfoCode) m_fValue = (float)g_infoManager.GetInt(m_iInfoCode);
+
+ proportion = (m_fValue - m_fStart) / (m_fEnd - m_fStart);
+ break;
+
+ case SPIN_CONTROL_TYPE_INT:
+ if (m_iInfoCode) m_iValue = g_infoManager.GetInt(m_iInfoCode);
+
+ proportion = (float)(m_iValue - m_iStart) / (float)(m_iEnd - m_iStart);
+ break;
+ default:
+ if (m_iInfoCode) m_iPercent = g_infoManager.GetInt(m_iInfoCode);
+ proportion = 0.01f * m_iPercent;
+ break;
+ }
+
+ float fScaleX = m_width == 0 ? 1.0f : m_width / m_guiBackground.GetTextureWidth();
+ float fScaleY = m_height == 0 ? 1.0f : m_height / m_guiBackground.GetTextureHeight();
+
+ m_guiBackground.SetHeight(m_height);
+ m_guiBackground.SetWidth(m_width);
+ m_guiBackground.Render();
+
+ float fWidth = (m_guiBackground.GetTextureWidth() - m_guiMid.GetTextureWidth())*fScaleX;
+
+ float fPos = m_guiBackground.GetXPosition() + proportion * fWidth;
+
+ if ((int)fWidth > 1)
+ {
+ if (m_bHasFocus)
+ {
+ m_guiMidFocus.SetPosition(fPos, m_guiBackground.GetYPosition() );
+ m_guiMidFocus.SetWidth(m_guiMidFocus.GetTextureWidth() * fScaleX);
+ m_guiMidFocus.SetHeight(m_guiMidFocus.GetTextureHeight() * fScaleY);
+ m_guiMidFocus.Render();
+ }
+ else
+ {
+ m_guiMid.SetPosition(fPos, m_guiBackground.GetYPosition() );
+ m_guiMid.SetWidth(m_guiMid.GetTextureWidth()*fScaleX);
+ m_guiMid.SetHeight(m_guiMid.GetTextureHeight()*fScaleY);
+ m_guiMid.Render();
+ }
+ }
+ }
+ CGUIControl::Render();
+}
+
+bool CGUISliderControl::OnMessage(CGUIMessage& message)
+{
+ if (message.GetControlId() == GetID() )
+ {
+ switch (message.GetMessage())
+ {
+ case GUI_MSG_ITEM_SELECT:
+ SetPercentage( message.GetParam1() );
+ return true;
+ break;
+
+ case GUI_MSG_LABEL_RESET:
+ {
+ SetPercentage(0);
+ return true;
+ }
+ break;
+ }
+ }
+
+ return CGUIControl::OnMessage(message);
+}
+
+bool CGUISliderControl::OnAction(const CAction &action)
+{
+ switch ( action.id )
+ {
+ case ACTION_MOVE_LEFT:
+ //case ACTION_OSD_SHOW_VALUE_MIN:
+ Move( -1);
+ return true;
+ break;
+
+ case ACTION_MOVE_RIGHT:
+ //case ACTION_OSD_SHOW_VALUE_PLUS:
+ Move(1);
+ return true;
+ break;
+ default:
+ return CGUIControl::OnAction(action);
+ }
+}
+
+void CGUISliderControl::Move(int iNumSteps)
+{
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_FLOAT:
+ m_fValue += m_fInterval * iNumSteps;
+ if (m_fValue < m_fStart) m_fValue = m_fStart;
+ if (m_fValue > m_fEnd) m_fValue = m_fEnd;
+ break;
+
+ case SPIN_CONTROL_TYPE_INT:
+ m_iValue += iNumSteps;
+ if (m_iValue < m_iStart) m_iValue = m_iStart;
+ if (m_iValue > m_iEnd) m_iValue = m_iEnd;
+ break;
+
+ default:
+ m_iPercent += iNumSteps;
+ if (m_iPercent < 0) m_iPercent = 0;
+ if (m_iPercent > 100) m_iPercent = 100;
+ break;
+ }
+ SEND_CLICK_MESSAGE(GetID(), GetParentID(), 0);
+}
+
+void CGUISliderControl::SetPercentage(int iPercent)
+{
+ if (iPercent > 100) iPercent = 100;
+ if (iPercent < 0) iPercent = 0;
+ m_iPercent = iPercent;
+}
+
+int CGUISliderControl::GetPercentage() const
+{
+ return m_iPercent;
+}
+
+void CGUISliderControl::SetIntValue(int iValue)
+{
+ if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
+ m_fValue = (float)iValue;
+ else if (m_iType == SPIN_CONTROL_TYPE_INT)
+ m_iValue = iValue;
+ else
+ SetPercentage(iValue);
+}
+
+int CGUISliderControl::GetIntValue() const
+{
+ if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
+ return (int)m_fValue;
+ else if (m_iType == SPIN_CONTROL_TYPE_INT)
+ return m_iValue;
+ else
+ return m_iPercent;
+}
+
+void CGUISliderControl::SetFloatValue(float fValue)
+{
+ if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
+ m_fValue = fValue;
+ else if (m_iType == SPIN_CONTROL_TYPE_INT)
+ m_iValue = (int)fValue;
+ else
+ SetPercentage((int)fValue);
+}
+
+float CGUISliderControl::GetFloatValue() const
+{
+ if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
+ return m_fValue;
+ else if (m_iType == SPIN_CONTROL_TYPE_INT)
+ return (float)m_iValue;
+ else
+ return (float)m_iPercent;
+}
+
+void CGUISliderControl::SetFloatInterval(float fInterval)
+{
+ m_fInterval = fInterval;
+}
+
+void CGUISliderControl::SetRange(int iStart, int iEnd)
+{
+ if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
+ SetFloatRange((float)iStart,(float)iEnd);
+ else
+ {
+ m_iStart = iStart;
+ m_iEnd = iEnd;
+ }
+}
+
+void CGUISliderControl::SetFloatRange(float fStart, float fEnd)
+{
+ if (m_iType == SPIN_CONTROL_TYPE_INT)
+ SetRange((int)fStart, (int)fEnd);
+ else
+ {
+ m_fStart = fStart;
+ m_fEnd = fEnd;
+ }
+}
+
+void CGUISliderControl::FreeResources()
+{
+ CGUIControl::FreeResources();
+ m_guiBackground.FreeResources();
+ m_guiMid.FreeResources();
+ m_guiMidFocus.FreeResources();
+}
+
+void CGUISliderControl::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+ m_guiBackground.DynamicResourceAlloc(bOnOff);
+ m_guiMid.DynamicResourceAlloc(bOnOff);
+ m_guiMidFocus.DynamicResourceAlloc(bOnOff);
+}
+
+void CGUISliderControl::AllocResources()
+{
+ CGUIControl::AllocResources();
+ m_guiBackground.AllocResources();
+ m_guiMid.AllocResources();
+ m_guiMidFocus.AllocResources();
+}
+
+bool CGUISliderControl::HitTest(const CPoint &point) const
+{
+ if (m_guiBackground.HitTest(point)) return true;
+ if (m_guiMid.HitTest(point)) return true;
+ return false;
+}
+
+void CGUISliderControl::SetFromPosition(const CPoint &point)
+{
+ float fPercent = (point.x - m_guiBackground.GetXPosition()) / m_guiBackground.GetWidth();
+ if (fPercent < 0) fPercent = 0;
+ if (fPercent > 1) fPercent = 1;
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_FLOAT:
+ m_fValue = m_fStart + (m_fEnd - m_fStart) * fPercent;
+ break;
+
+ case SPIN_CONTROL_TYPE_INT:
+ m_iValue = (int)(m_iStart + (float)(m_iEnd - m_iStart) * fPercent + 0.49f);
+ break;
+
+ default:
+ m_iPercent = (int)(fPercent * 100 + 0.49f);
+ break;
+ }
+ SEND_CLICK_MESSAGE(GetID(), GetParentID(), 0);
+}
+
+bool CGUISliderControl::OnMouseClick(int button, const CPoint &point)
+{
+ g_Mouse.SetState(MOUSE_STATE_CLICK);
+ // turn off any exclusive access, if it's on...
+ g_Mouse.EndExclusiveAccess(GetID(), GetParentID());
+ if (m_guiBackground.HitTest(point))
+ { // set the position
+ SetFromPosition(point);
+ return true;
+ }
+ return false;
+}
+
+bool CGUISliderControl::OnMouseDrag(const CPoint &offset, const CPoint &point)
+{
+ g_Mouse.SetState(MOUSE_STATE_DRAG);
+ // get exclusive access to the mouse
+ g_Mouse.SetExclusiveAccess(GetID(), GetParentID(), point);
+ // get the position of the mouse
+ SetFromPosition(point);
+ return true;
+}
+
+bool CGUISliderControl::OnMouseWheel(char wheel, const CPoint &point)
+{ // move the slider 10 steps in the appropriate direction
+ Move(wheel*10);
+ return true;
+}
+
+void CGUISliderControl::SetInfo(int iInfo)
+{
+ m_iInfoCode = iInfo;
+}
+
+CStdString CGUISliderControl::GetDescription() const
+{
+ if (!m_textValue.IsEmpty())
+ return m_textValue;
+ CStdString description;
+ if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
+ description.Format("%2.2f", m_fValue);
+ else if (m_iType == SPIN_CONTROL_TYPE_INT)
+ description.Format("%i", m_iValue);
+ else
+ description.Format("%i%%", m_iPercent);
+ return description;
+}
+
+void CGUISliderControl::UpdateColors()
+{
+ CGUIControl::UpdateColors();
+ m_guiBackground.SetDiffuseColor(m_diffuseColor);
+ m_guiMid.SetDiffuseColor(m_diffuseColor);
+ m_guiMidFocus.SetDiffuseColor(m_diffuseColor);
+}
+
diff --git a/guilib/GUISliderControl.h b/guilib/GUISliderControl.h
new file mode 100644
index 0000000000..cab440021c
--- /dev/null
+++ b/guilib/GUISliderControl.h
@@ -0,0 +1,98 @@
+/*!
+\file GUISliderControl.h
+\brief
+*/
+
+#ifndef GUILIB_GUISLIDERCONTROL_H
+#define GUILIB_GUISLIDERCONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+#include "GUITexture.h"
+
+#define SPIN_CONTROL_TYPE_INT 1
+#define SPIN_CONTROL_TYPE_FLOAT 2
+#define SPIN_CONTROL_TYPE_TEXT 3
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUISliderControl :
+ public CGUIControl
+{
+public:
+ CGUISliderControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& backGroundTexture, const CTextureInfo& mibTexture, const CTextureInfo& nibTextureFocus, int iType);
+ virtual ~CGUISliderControl(void);
+ virtual CGUISliderControl *Clone() const { return new CGUISliderControl(*this); };
+
+ virtual void Render();
+ virtual bool OnAction(const CAction &action);
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual void SetRange(int iStart, int iEnd);
+ virtual void SetFloatRange(float fStart, float fEnd);
+ virtual bool OnMessage(CGUIMessage& message);
+ void SetInfo(int iInfo);
+ void SetPercentage(int iPercent);
+ int GetPercentage() const;
+ void SetIntValue(int iValue);
+ int GetIntValue() const;
+ void SetFloatValue(float fValue);
+ float GetFloatValue() const;
+ void SetFloatInterval(float fInterval);
+ void SetType(int iType) { m_iType = iType; };
+ virtual bool HitTest(const CPoint &point) const;
+ virtual bool OnMouseClick(int button, const CPoint &point);
+ virtual bool OnMouseDrag(const CPoint &offset, const CPoint &point);
+ virtual bool OnMouseWheel(char wheel, const CPoint &point);
+ virtual CStdString GetDescription() const;
+ void SetTextValue(const CStdString &textValue) { m_textValue = textValue; };
+protected:
+ virtual void UpdateColors();
+ virtual void Move(int iNumSteps);
+ virtual void SetFromPosition(const CPoint &point);
+
+ CGUITexture m_guiBackground;
+ CGUITexture m_guiMid;
+ CGUITexture m_guiMidFocus;
+ int m_iType;
+
+ int m_iPercent;
+
+ int m_iValue;
+ int m_iStart;
+ int m_iEnd;
+
+ float m_fValue;
+ float m_fStart;
+ float m_fInterval;
+ float m_fEnd;
+
+ int m_iInfoCode;
+ CStdString m_textValue; ///< Allows overriding of the text value to be displayed (parent must update when the slider updates)
+};
+#endif
diff --git a/guilib/GUISound.cpp b/guilib/GUISound.cpp
new file mode 100644
index 0000000000..8d80aa6d8e
--- /dev/null
+++ b/guilib/GUISound.cpp
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "GUISound.h"
+#include "AudioContext.h"
+#include "Settings.h"
+#include "FileSystem/File.h"
+#include "utils/log.h"
+#ifdef HAS_SDL_AUDIO
+#include <SDL/SDL_mixer.h>
+#include "FileSystem/SpecialProtocol.h"
+#endif
+#ifndef HAS_SDL_AUDIO
+
+typedef struct
+{
+ char chunk_id[4];
+ long chunksize;
+} WAVE_CHUNK;
+
+typedef struct
+{
+ char riff[4];
+ long filesize;
+ char rifftype[4];
+} WAVE_RIFFHEADER;
+#else
+#define GUI_SOUND_CHANNEL 0
+#endif
+
+CGUISound::CGUISound()
+{
+ m_soundBuffer=NULL;
+}
+
+CGUISound::~CGUISound()
+{
+#ifdef _WIN32
+ FreeBuffer();
+#elif defined(HAS_SDL_AUDIO)
+ Mix_FreeChunk(m_soundBuffer);
+#endif
+}
+
+// \brief Loads a wav file by filename
+bool CGUISound::Load(const CStdString& strFile)
+{
+#ifdef _WIN32
+ LPBYTE pbData=NULL;
+ WAVEFORMATEX wfx;
+ int size=0;
+ if (!LoadWav(strFile, &wfx, &pbData, &size))
+ return false;
+
+ bool bReady=(CreateBuffer(&wfx, size) && FillBuffer(pbData, size));
+
+ if (!bReady)
+ FreeBuffer();
+
+ delete[] pbData;
+
+ return bReady;
+#elif defined(HAS_SDL_AUDIO)
+ m_soundBuffer = Mix_LoadWAV(_P(strFile));
+ if (!m_soundBuffer)
+ return false;
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+// \brief Starts playback of the sound
+void CGUISound::Play()
+{
+ if (m_soundBuffer)
+ {
+#ifdef _WIN32
+ m_soundBuffer->Play(0, 0, 0);
+#elif defined(HAS_SDL_AUDIO)
+ Mix_PlayChannel(GUI_SOUND_CHANNEL, m_soundBuffer, 0);
+#endif
+ }
+}
+
+// \brief returns true if the sound is playing
+bool CGUISound::IsPlaying()
+{
+#ifdef _WIN32
+ if (m_soundBuffer)
+ {
+ DWORD dwStatus;
+ m_soundBuffer->GetStatus(&dwStatus);
+ return (dwStatus & DSBSTATUS_PLAYING);
+ }
+
+ return false;
+#elif defined(HAS_SDL_AUDIO)
+ return Mix_Playing(GUI_SOUND_CHANNEL) != 0;
+#else
+ return false;
+#endif
+}
+
+// \brief Stops playback if the sound
+void CGUISound::Stop()
+{
+ if (m_soundBuffer)
+ {
+#ifdef _WIN32
+ m_soundBuffer->Stop();
+#elif defined(HAS_SDL_AUDIO)
+ Mix_HaltChannel(GUI_SOUND_CHANNEL);
+#endif
+
+ while(IsPlaying()) {}
+ }
+}
+
+// \brief Sets the volume of the sound
+void CGUISound::SetVolume(int level)
+{
+ if (m_soundBuffer)
+ {
+#ifdef _WIN32
+ m_soundBuffer->SetVolume(level);
+#elif defined(HAS_SDL_AUDIO)
+ Mix_Volume(GUI_SOUND_CHANNEL, level);
+#endif
+ }
+}
+
+#ifdef _WIN32
+bool CGUISound::CreateBuffer(LPWAVEFORMATEX wfx, int iLength)
+{
+ // Set up DSBUFFERDESC structure
+ DSBUFFERDESC dsbdesc;
+ memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
+ dsbdesc.dwSize=sizeof(DSBUFFERDESC);
+ // directsound requires ctrlvolume to be set
+ dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME;
+ dsbdesc.dwBufferBytes=iLength;
+ dsbdesc.lpwfxFormat=wfx;
+
+ LPDIRECTSOUND directSound=g_audioContext.GetDirectSoundDevice();
+ if (!directSound)
+ return false;
+
+ // Create buffer
+ if (FAILED(directSound->CreateSoundBuffer(&dsbdesc, &m_soundBuffer, NULL)))
+ {
+ m_soundBuffer = NULL;
+ CLog::Log(LOGERROR, __FUNCTION__" Creating sound buffer failed!");
+ return false;
+ }
+
+ // Make effects as loud as possible
+ m_soundBuffer->SetVolume(g_stSettings.m_nVolumeLevel);
+
+ return true;
+}
+
+bool CGUISound::FillBuffer(LPBYTE pbData, int iLength)
+{
+ if (!m_soundBuffer)
+ return false;
+
+ LPVOID lpvWrite;
+ DWORD dwLength;
+
+ if (SUCCEEDED(m_soundBuffer->Lock(0, 0, &lpvWrite, &dwLength, NULL, NULL, DSBLOCK_ENTIREBUFFER)))
+ {
+ memcpy(lpvWrite, pbData, iLength);
+ m_soundBuffer->Unlock(lpvWrite, dwLength, NULL, 0);
+ return true;
+ }
+
+ CLog::Log(LOGERROR, __FUNCTION__" Filling sound buffer failed!");
+
+ return false;
+}
+
+void CGUISound::FreeBuffer()
+{
+ if (IsPlaying())
+ Stop();
+
+ SAFE_RELEASE(m_soundBuffer);
+}
+
+bool CGUISound::LoadWav(const CStdString& strFile, WAVEFORMATEX* wfx, LPBYTE* ppWavData, int* pDataSize)
+{
+ XFILE::CFile file;
+ if (!file.Open(strFile))
+ return false;
+
+ // read header
+ WAVE_RIFFHEADER riffh;
+ file.Read(&riffh, sizeof(WAVE_RIFFHEADER));
+
+ // file valid?
+ if (strncmp(riffh.riff, "RIFF", 4)!=0 && strncmp(riffh.rifftype, "WAVE", 4)!=0)
+ {
+ file.Close();
+ return false;
+ }
+
+ long offset=0;
+ offset += sizeof(WAVE_RIFFHEADER);
+ offset -= sizeof(WAVE_CHUNK);
+
+ // parse chunks
+ do
+ {
+ WAVE_CHUNK chunk;
+
+ // always seeking to the start of a chunk
+ file.Seek(offset + sizeof(WAVE_CHUNK), SEEK_SET);
+ file.Read(&chunk, sizeof(WAVE_CHUNK));
+
+ if (!strncmp(chunk.chunk_id, "fmt ", 4))
+ { // format chunk
+ memset(wfx, 0, sizeof(WAVEFORMATEX));
+ file.Read(wfx, 16);
+ // we only need 16 bytes of the fmt chunk
+ if (chunk.chunksize-16>0)
+ file.Seek(chunk.chunksize-16, SEEK_CUR);
+ }
+ else if (!strncmp(chunk.chunk_id, "data", 4))
+ { // data chunk
+ *ppWavData=new BYTE[chunk.chunksize+1];
+ file.Read(*ppWavData, chunk.chunksize);
+ *pDataSize=chunk.chunksize;
+
+ if (chunk.chunksize & 1)
+ offset++;
+ }
+ else
+ { // other chunk - unused, just skip
+ file.Seek(chunk.chunksize, SEEK_CUR);
+ }
+
+ offset+=(chunk.chunksize+sizeof(WAVE_CHUNK));
+
+ if (offset & 1)
+ offset++;
+
+ } while (offset+(int)sizeof(WAVE_CHUNK) < riffh.filesize);
+
+ file.Close();
+ return (*ppWavData!=NULL);
+}
+
+#endif
diff --git a/guilib/GUISound.h b/guilib/GUISound.h
new file mode 100644
index 0000000000..3103afe1da
--- /dev/null
+++ b/guilib/GUISound.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#pragma once
+
+#include "StdString.h"
+
+#ifdef HAS_SDL_AUDIO
+#include <SDL/SDL_mixer.h>
+#endif
+
+class CGUISound
+{
+public:
+ CGUISound();
+ virtual ~CGUISound();
+
+ bool Load(const CStdString& strFile);
+ void Play();
+ void Stop();
+ bool IsPlaying();
+ void SetVolume(int level);
+
+private:
+#ifdef _WIN32
+ bool LoadWav(const CStdString& strFile, WAVEFORMATEX* wfx, LPBYTE* ppWavData, int* pDataSize);
+ bool CreateBuffer(LPWAVEFORMATEX wfx, int iLength);
+ bool FillBuffer(LPBYTE pbData, int iLength);
+ void FreeBuffer();
+
+ LPDIRECTSOUNDBUFFER m_soundBuffer;
+#elif defined(HAS_SDL_AUDIO)
+ Mix_Chunk* m_soundBuffer;
+#else
+ void *m_soundBuffer;
+#endif
+};
diff --git a/guilib/GUISpinControl.cpp b/guilib/GUISpinControl.cpp
new file mode 100644
index 0000000000..bca3947d56
--- /dev/null
+++ b/guilib/GUISpinControl.cpp
@@ -0,0 +1,939 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUISpinControl.h"
+#include "utils/CharsetConverter.h"
+#include "MouseStat.h"
+#include "Key.h"
+
+using namespace std;
+
+#define SPIN_BUTTON_DOWN 1
+#define SPIN_BUTTON_UP 2
+
+CGUISpinControl::CGUISpinControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& textureUp, const CTextureInfo& textureDown, const CTextureInfo& textureUpFocus, const CTextureInfo& textureDownFocus, const CLabelInfo &labelInfo, int iType)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+ , m_imgspinUp(posX, posY, width, height, textureUp)
+ , m_imgspinDown(posX, posY, width, height, textureDown)
+ , m_imgspinUpFocus(posX, posY, width, height, textureUpFocus)
+ , m_imgspinDownFocus(posX, posY, width, height, textureDownFocus)
+ , m_textLayout(labelInfo.font, false)
+{
+ m_bReverse = false;
+ m_iStart = 0;
+ m_iEnd = 100;
+ m_fStart = 0.0f;
+ m_fEnd = 1.0f;
+ m_fInterval = 0.1f;
+ m_iValue = 0;
+ m_label = labelInfo;
+ m_label.align |= XBFONT_CENTER_Y;
+ m_fValue = 0.0;
+ m_iType = iType;
+ m_iSelect = SPIN_BUTTON_DOWN;
+ m_bShowRange = false;
+ m_iTypedPos = 0;
+ strcpy(m_szTyped, "");
+ ControlType = GUICONTROL_SPIN;
+ m_currentItem = 0;
+ m_numItems = 10;
+ m_itemsPerPage = 10;
+ m_showOnePage = true;
+}
+
+CGUISpinControl::~CGUISpinControl(void)
+{}
+
+bool CGUISpinControl::OnAction(const CAction &action)
+{
+ switch (action.id)
+ {
+ case REMOTE_0:
+ case REMOTE_1:
+ case REMOTE_2:
+ case REMOTE_3:
+ case REMOTE_4:
+ case REMOTE_5:
+ case REMOTE_6:
+ case REMOTE_7:
+ case REMOTE_8:
+ case REMOTE_9:
+ {
+ if (strlen(m_szTyped) >= 3)
+ {
+ m_iTypedPos = 0;
+ strcpy(m_szTyped, "");
+ }
+ int iNumber = action.id - REMOTE_0;
+
+ m_szTyped[m_iTypedPos] = iNumber + '0';
+ m_iTypedPos++;
+ m_szTyped[m_iTypedPos] = 0;
+ int iValue;
+ sscanf(m_szTyped, "%i", &iValue);
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_INT:
+ {
+ if (iValue < m_iStart || iValue > m_iEnd)
+ {
+ m_iTypedPos = 0;
+ m_szTyped[m_iTypedPos] = iNumber + '0';
+ m_iTypedPos++;
+ m_szTyped[m_iTypedPos] = 0;
+ sscanf(m_szTyped, "%i", &iValue);
+ if (iValue < m_iStart || iValue > m_iEnd)
+ {
+ m_iTypedPos = 0;
+ strcpy(m_szTyped, "");
+ return true;
+ }
+ }
+ m_iValue = iValue;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_TEXT:
+ {
+ if (iValue < 0 || iValue >= (int)m_vecLabels.size())
+ {
+ m_iTypedPos = 0;
+ m_szTyped[m_iTypedPos] = iNumber + '0';
+ m_iTypedPos++;
+ m_szTyped[m_iTypedPos] = 0;
+ sscanf(m_szTyped, "%i", &iValue);
+ if (iValue < 0 || iValue >= (int)m_vecLabels.size())
+ {
+ m_iTypedPos = 0;
+ strcpy(m_szTyped, "");
+ return true;
+ }
+ }
+ m_iValue = iValue;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ }
+ break;
+
+ }
+ return true;
+ }
+ break;
+ case ACTION_PAGE_UP:
+ if (!m_bReverse)
+ PageDown();
+ else
+ PageUp();
+ return true;
+ break;
+ case ACTION_PAGE_DOWN:
+ if (!m_bReverse)
+ PageUp();
+ else
+ PageDown();
+ return true;
+ break;
+ case ACTION_SELECT_ITEM:
+ if (m_iSelect == SPIN_BUTTON_UP)
+ {
+ MoveUp();
+ return true;
+ }
+ if (m_iSelect == SPIN_BUTTON_DOWN)
+ {
+ MoveDown();
+ return true;
+ }
+ break;
+ }
+/* static float m_fSmoothScrollOffset = 0.0f;
+ if (action.id == ACTION_SCROLL_UP)
+ {
+ m_fSmoothScrollOffset += action.amount1 * action.amount1;
+ bool handled = false;
+ while (m_fSmoothScrollOffset > 0.4)
+ {
+ handled = true;
+ m_fSmoothScrollOffset -= 0.4f;
+ MoveDown();
+ }
+ return handled;
+ }*/
+ return CGUIControl::OnAction(action);
+}
+
+void CGUISpinControl::OnLeft()
+{
+ if (m_iSelect == SPIN_BUTTON_UP)
+ {
+ // select the down button
+ m_iSelect = SPIN_BUTTON_DOWN;
+ }
+ else
+ { // base class
+ CGUIControl::OnLeft();
+ }
+}
+
+void CGUISpinControl::OnRight()
+{
+ if (m_iSelect == SPIN_BUTTON_DOWN)
+ {
+ // select the up button
+ m_iSelect = SPIN_BUTTON_UP;
+ }
+ else
+ { // base class
+ CGUIControl::OnRight();
+ }
+}
+
+void CGUISpinControl::Clear()
+{
+ m_vecLabels.erase(m_vecLabels.begin(), m_vecLabels.end());
+ m_vecValues.erase(m_vecValues.begin(), m_vecValues.end());
+ SetValue(0);
+}
+
+bool CGUISpinControl::OnMessage(CGUIMessage& message)
+{
+ if (CGUIControl::OnMessage(message) )
+ return true;
+ if (message.GetControlId() == GetID() )
+ {
+ switch (message.GetMessage())
+ {
+ case GUI_MSG_ITEM_SELECT:
+ if (SPIN_CONTROL_TYPE_PAGE == m_iType)
+ {
+ m_currentItem = message.GetParam1();
+ return true;
+ }
+ SetValue( message.GetParam1());
+ if (message.GetParam2() == SPIN_BUTTON_DOWN || message.GetParam2() == SPIN_BUTTON_UP)
+ m_iSelect = message.GetParam2();
+ return true;
+ break;
+
+ case GUI_MSG_LABEL_RESET:
+ if (SPIN_CONTROL_TYPE_PAGE == m_iType)
+ {
+ m_itemsPerPage = message.GetParam1();
+ m_numItems = message.GetParam2();
+ return true;
+ }
+ {
+ Clear();
+ return true;
+ }
+ break;
+
+ case GUI_MSG_SHOWRANGE:
+ if (message.GetParam1() )
+ m_bShowRange = true;
+ else
+ m_bShowRange = false;
+ break;
+
+ case GUI_MSG_LABEL_ADD:
+ {
+ AddLabel(message.GetLabel(), message.GetParam1());
+ return true;
+ }
+ break;
+
+ case GUI_MSG_ITEM_SELECTED:
+ {
+ message.SetParam1( GetValue() );
+ message.SetParam2(m_iSelect);
+
+ if (m_iType == SPIN_CONTROL_TYPE_TEXT)
+ {
+ if ( m_iValue >= 0 && m_iValue < (int)m_vecLabels.size() )
+ message.SetLabel( m_vecLabels[m_iValue]);
+ }
+ return true;
+ }
+
+ case GUI_MSG_PAGE_UP:
+ if (CanMoveUp())
+ MoveUp();
+ return true;
+
+ case GUI_MSG_PAGE_DOWN:
+ if (CanMoveDown())
+ MoveDown();
+ return true;
+
+ case GUI_MSG_MOVE_OFFSET:
+ {
+ int count = (int)message.GetParam1();
+ while (count < 0)
+ {
+ MoveUp();
+ count++;
+ }
+ while (count > 0)
+ {
+ MoveDown();
+ count--;
+ }
+ return true;
+ }
+
+ }
+ }
+ return false;
+}
+
+void CGUISpinControl::AllocResources()
+{
+ CGUIControl::AllocResources();
+ m_imgspinUp.AllocResources();
+ m_imgspinUpFocus.AllocResources();
+ m_imgspinDown.AllocResources();
+ m_imgspinDownFocus.AllocResources();
+
+ m_imgspinDownFocus.SetPosition(m_posX, m_posY);
+ m_imgspinDown.SetPosition(m_posX, m_posY);
+ m_imgspinUp.SetPosition(m_posX + m_imgspinDown.GetWidth(), m_posY);
+ m_imgspinUpFocus.SetPosition(m_posX + m_imgspinDownFocus.GetWidth(), m_posY);
+}
+
+void CGUISpinControl::FreeResources()
+{
+ CGUIControl::FreeResources();
+ m_imgspinUp.FreeResources();
+ m_imgspinUpFocus.FreeResources();
+ m_imgspinDown.FreeResources();
+ m_imgspinDownFocus.FreeResources();
+ m_iTypedPos = 0;
+ strcpy(m_szTyped, "");
+}
+
+void CGUISpinControl::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIControl::DynamicResourceAlloc(bOnOff);
+ m_imgspinUp.DynamicResourceAlloc(bOnOff);
+ m_imgspinUpFocus.DynamicResourceAlloc(bOnOff);
+ m_imgspinDown.DynamicResourceAlloc(bOnOff);
+ m_imgspinDownFocus.DynamicResourceAlloc(bOnOff);
+}
+
+void CGUISpinControl::Render()
+{
+ if (!HasFocus())
+ {
+ m_iTypedPos = 0;
+ strcpy(m_szTyped, "");
+ }
+
+ float posX = m_posX;
+ CStdString text;
+ CStdStringW strTextUnicode;
+
+ if (m_iType == SPIN_CONTROL_TYPE_INT)
+ {
+ if (m_bShowRange)
+ {
+ text.Format("%i/%i", m_iValue, m_iEnd);
+ }
+ else
+ {
+ text.Format("%i", m_iValue);
+ }
+ }
+ else if (m_iType == SPIN_CONTROL_TYPE_PAGE)
+ {
+ // work out number of pages and current page
+ int numPages = (m_numItems + m_itemsPerPage - 1) / m_itemsPerPage;
+ int currentPage = m_currentItem / m_itemsPerPage + 1;
+ if (m_currentItem >= m_numItems - m_itemsPerPage)
+ currentPage = numPages;
+ text.Format("%i/%i", currentPage, numPages);
+ }
+ else if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
+ {
+ if (m_bShowRange)
+ {
+ text.Format("%02.2f/%02.2f", m_fValue, m_fEnd);
+ }
+ else
+ {
+ text.Format("%02.2f", m_fValue);
+ }
+ }
+ else
+ {
+ if (m_iValue >= 0 && m_iValue < (int)m_vecLabels.size() )
+ {
+ if (m_bShowRange)
+ {
+ text.Format("(%i/%i) %s", m_iValue + 1, (int)m_vecLabels.size(), CStdString(m_vecLabels[m_iValue]).c_str() );
+ }
+ else
+ {
+ text.Format("%s", CStdString(m_vecLabels[m_iValue]).c_str() );
+ }
+ }
+ else text.Format("?%i?", m_iValue);
+
+ }
+
+ m_textLayout.Update(text);
+ // Calculate the size of our text (for use in HitTest)
+ float fTextWidth = 0;
+ float fTextHeight = 0;
+ m_textLayout.GetTextExtent(fTextWidth, fTextHeight);
+ // Position the arrows
+ if ( !(m_label.align & (XBFONT_RIGHT | XBFONT_CENTER_X)) )
+ {
+ m_imgspinUpFocus.SetPosition(fTextWidth + 5 + posX + m_imgspinDown.GetWidth(), m_posY);
+ m_imgspinUp.SetPosition(fTextWidth + 5 + posX + m_imgspinDown.GetWidth(), m_posY);
+ m_imgspinDownFocus.SetPosition(fTextWidth + 5 + posX, m_posY);
+ m_imgspinDown.SetPosition(fTextWidth + 5 + posX, m_posY);
+ }
+
+ if ( HasFocus() )
+ {
+ if (m_iSelect == SPIN_BUTTON_UP)
+ m_imgspinUpFocus.Render();
+ else
+ m_imgspinUp.Render();
+
+ if (m_iSelect == SPIN_BUTTON_DOWN)
+ m_imgspinDownFocus.Render();
+ else
+ m_imgspinDown.Render();
+ }
+ else
+ {
+ m_imgspinUp.Render();
+ m_imgspinDown.Render();
+ }
+
+ if (m_label.font)
+ {
+ float fPosY;
+ if (m_label.align & XBFONT_CENTER_Y)
+ fPosY = m_posY + m_height * 0.5f;
+ else
+ fPosY = m_posY + m_label.offsetY;
+
+ float fPosX = m_posX + m_label.offsetX - 3;
+ if (IsDisabled())
+ m_textLayout.Render(fPosX, fPosY, 0, m_label.disabledColor, m_label.shadowColor, m_label.align, 0, true);
+ else if (HasFocus() && m_label.focusedColor)
+ m_textLayout.Render(fPosX, fPosY, 0, m_label.focusedColor, m_label.shadowColor, m_label.align, 0);
+ else
+ m_textLayout.Render(fPosX, fPosY, 0, m_label.textColor, m_label.shadowColor, m_label.align, 0);
+
+ // set our hit rectangle for MouseOver events
+ if (!(m_label.align & (XBFONT_RIGHT | XBFONT_CENTER_X)))
+ m_hitRect.SetRect(fPosX, fPosY, fPosX + fTextWidth, fPosY + fTextHeight);
+ else
+ m_hitRect.SetRect(fPosX - fTextWidth, fPosY, fPosX, fPosY + fTextHeight);
+ }
+ CGUIControl::Render();
+}
+
+void CGUISpinControl::SetRange(int iStart, int iEnd)
+{
+ m_iStart = iStart;
+ m_iEnd = iEnd;
+}
+
+
+void CGUISpinControl::SetFloatRange(float fStart, float fEnd)
+{
+ m_fStart = fStart;
+ m_fEnd = fEnd;
+}
+
+void CGUISpinControl::SetValueFromLabel(const CStdString &label)
+{
+ if (m_iType == SPIN_CONTROL_TYPE_TEXT)
+ {
+ m_iValue = 0;
+ for (unsigned int i = 0; i < m_vecLabels.size(); i++)
+ if (label == m_vecLabels[i])
+ m_iValue = i;
+ }
+ else
+ m_iValue = atoi(label.c_str());
+}
+
+void CGUISpinControl::SetValue(int iValue)
+{
+ if (m_iType == SPIN_CONTROL_TYPE_TEXT)
+ {
+ m_iValue = 0;
+ for (unsigned int i = 0; i < m_vecValues.size(); i++)
+ if (iValue == m_vecValues[i])
+ m_iValue = i;
+ }
+ else
+ m_iValue = iValue;
+}
+
+void CGUISpinControl::SetFloatValue(float fValue)
+{
+ m_fValue = fValue;
+}
+
+int CGUISpinControl::GetValue() const
+{
+ if (m_iType == SPIN_CONTROL_TYPE_TEXT)
+ {
+ if (m_iValue >= 0 && m_iValue < (int)m_vecValues.size())
+ return m_vecValues[m_iValue];
+ }
+ return m_iValue;
+}
+
+float CGUISpinControl::GetFloatValue() const
+{
+ return m_fValue;
+}
+
+
+void CGUISpinControl::AddLabel(const string& strLabel, int iValue)
+{
+ m_vecLabels.push_back(strLabel);
+ m_vecValues.push_back(iValue);
+}
+
+const string CGUISpinControl::GetLabel() const
+{
+ if (m_iValue >= 0 && m_iValue < (int)m_vecLabels.size())
+ {
+ return m_vecLabels[ m_iValue];
+ }
+ return "";
+}
+
+void CGUISpinControl::SetPosition(float posX, float posY)
+{
+ CGUIControl::SetPosition(posX, posY);
+
+ m_imgspinDownFocus.SetPosition(posX, posY);
+ m_imgspinDown.SetPosition(posX, posY);
+
+ m_imgspinUp.SetPosition(m_posX + m_imgspinDown.GetWidth(), m_posY);
+ m_imgspinUpFocus.SetPosition(m_posX + m_imgspinDownFocus.GetWidth(), m_posY);
+
+}
+
+float CGUISpinControl::GetWidth() const
+{
+ return m_imgspinDown.GetWidth() * 2 ;
+}
+
+bool CGUISpinControl::CanMoveUp(bool bTestReverse)
+{
+ // test for reverse...
+ if (bTestReverse && m_bReverse) return CanMoveDown(false);
+
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_PAGE:
+ return m_currentItem > 0;
+ case SPIN_CONTROL_TYPE_INT:
+ {
+ if (m_iValue - 1 >= m_iStart)
+ return true;
+ return false;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_FLOAT:
+ {
+ if (m_fValue - m_fInterval >= m_fStart)
+ return true;
+ return false;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_TEXT:
+ {
+ if (m_iValue - 1 >= 0)
+ return true;
+ return false;
+ }
+ break;
+ }
+ return false;
+}
+
+bool CGUISpinControl::CanMoveDown(bool bTestReverse)
+{
+ // test for reverse...
+ if (bTestReverse && m_bReverse) return CanMoveUp(false);
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_PAGE:
+ return m_currentItem < m_numItems;
+ case SPIN_CONTROL_TYPE_INT:
+ {
+ if (m_iValue + 1 <= m_iEnd)
+ return true;
+ return false;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_FLOAT:
+ {
+ if (m_fValue + m_fInterval <= m_fEnd)
+ return true;
+ return false;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_TEXT:
+ {
+ if (m_iValue + 1 < (int)m_vecLabels.size())
+ return true;
+ return false;
+ }
+ break;
+ }
+ return false;
+}
+
+void CGUISpinControl::PageUp()
+{
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_INT:
+ {
+ if (m_iValue - 10 >= m_iStart)
+ m_iValue -= 10;
+ else
+ m_iValue = m_iStart;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+ case SPIN_CONTROL_TYPE_PAGE:
+ ChangePage(-10);
+ break;
+ case SPIN_CONTROL_TYPE_TEXT:
+ {
+ if (m_iValue - 10 >= 0)
+ m_iValue -= 10;
+ else
+ m_iValue = 0;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+ }
+
+}
+
+void CGUISpinControl::PageDown()
+{
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_INT:
+ {
+ if (m_iValue + 10 <= m_iEnd)
+ m_iValue += 10;
+ else
+ m_iValue = m_iEnd;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+ case SPIN_CONTROL_TYPE_PAGE:
+ ChangePage(10);
+ break;
+ case SPIN_CONTROL_TYPE_TEXT:
+ {
+ if (m_iValue + 10 < (int)m_vecLabels.size() )
+ m_iValue += 10;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ }
+ break;
+ }
+}
+
+void CGUISpinControl::MoveUp(bool bTestReverse)
+{
+ if (bTestReverse && m_bReverse)
+ { // actually should move down.
+ MoveDown(false);
+ return ;
+ }
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_INT:
+ {
+ if (m_iValue - 1 >= m_iStart)
+ m_iValue--;
+ else if (m_iValue == m_iStart)
+ m_iValue = m_iEnd;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_PAGE:
+ ChangePage(-1);
+ break;
+
+ case SPIN_CONTROL_TYPE_FLOAT:
+ {
+ if (m_fValue - m_fInterval >= m_fStart)
+ m_fValue -= m_fInterval;
+ else if (m_fValue - m_fInterval < m_fStart)
+ m_fValue = m_fEnd;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_TEXT:
+ {
+ if (m_iValue - 1 >= 0)
+ m_iValue--;
+ else if (m_iValue == 0)
+ m_iValue = (int)m_vecLabels.size() - 1;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+ }
+}
+
+void CGUISpinControl::MoveDown(bool bTestReverse)
+{
+ if (bTestReverse && m_bReverse)
+ { // actually should move up.
+ MoveUp(false);
+ return ;
+ }
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_INT:
+ {
+ if (m_iValue + 1 <= m_iEnd)
+ m_iValue++;
+ else if (m_iValue == m_iEnd)
+ m_iValue = m_iStart;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_PAGE:
+ ChangePage(1);
+ break;
+
+ case SPIN_CONTROL_TYPE_FLOAT:
+ {
+ if (m_fValue + m_fInterval <= m_fEnd)
+ m_fValue += m_fInterval;
+ else if (m_fValue + m_fInterval > m_fEnd)
+ m_fValue = m_fStart;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+
+ case SPIN_CONTROL_TYPE_TEXT:
+ {
+ if (m_iValue + 1 < (int)m_vecLabels.size() )
+ m_iValue++;
+ else if (m_iValue == (int)m_vecLabels.size() - 1)
+ m_iValue = 0;
+ CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
+ SendWindowMessage(msg);
+ return ;
+ }
+ break;
+ }
+}
+void CGUISpinControl::SetReverse(bool bReverse)
+{
+ m_bReverse = bReverse;
+}
+
+void CGUISpinControl::SetFloatInterval(float fInterval)
+{
+ m_fInterval = fInterval;
+}
+
+void CGUISpinControl::SetShowRange(bool bOnoff)
+{
+ m_bShowRange = bOnoff;
+}
+
+int CGUISpinControl::GetMinimum() const
+{
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_PAGE:
+ return 0;
+ case SPIN_CONTROL_TYPE_INT:
+ return m_iStart;
+ break;
+
+ case SPIN_CONTROL_TYPE_TEXT:
+ return 1;
+ break;
+
+ case SPIN_CONTROL_TYPE_FLOAT:
+ return (int)(m_fStart*10.0f);
+ break;
+ }
+ return 0;
+}
+
+int CGUISpinControl::GetMaximum() const
+{
+ switch (m_iType)
+ {
+ case SPIN_CONTROL_TYPE_PAGE:
+ return m_numItems;
+ case SPIN_CONTROL_TYPE_INT:
+ return m_iEnd;
+ break;
+
+ case SPIN_CONTROL_TYPE_TEXT:
+ return (int)m_vecLabels.size();
+ break;
+
+ case SPIN_CONTROL_TYPE_FLOAT:
+ return (int)(m_fEnd*10.0f);
+ break;
+ }
+ return 100;
+}
+
+bool CGUISpinControl::HitTest(const CPoint &point) const
+{
+ if (m_imgspinUpFocus.HitTest(point) || m_imgspinDownFocus.HitTest(point))
+ return true;
+ return CGUIControl::HitTest(point);
+}
+
+bool CGUISpinControl::OnMouseOver(const CPoint &point)
+{
+ if (m_imgspinUpFocus.HitTest(point))
+ {
+ CGUIControl::OnMouseOver(point);
+ m_iSelect = SPIN_BUTTON_UP;
+ }
+ else if (m_imgspinDownFocus.HitTest(point))
+ {
+ CGUIControl::OnMouseOver(point);
+ m_iSelect = SPIN_BUTTON_DOWN;
+ }
+ else
+ {
+ CGUIControl::OnMouseOver(point);
+ m_iSelect = SPIN_BUTTON_UP;
+ }
+ return true;
+}
+
+bool CGUISpinControl::OnMouseClick(int button, const CPoint &point)
+{ // only left button handled
+ if (button != MOUSE_LEFT_BUTTON) return false;
+ if (m_imgspinUpFocus.HitTest(point))
+ {
+ MoveUp();
+ }
+ if (m_imgspinDownFocus.HitTest(point))
+ {
+ MoveDown();
+ }
+ return true;
+}
+
+bool CGUISpinControl::OnMouseWheel(char wheel, const CPoint &point)
+{
+ for (int i = 0; i < abs(wheel); i++)
+ {
+ if (wheel > 0)
+ {
+ MoveUp();
+ }
+ else
+ {
+ MoveDown();
+ }
+ }
+ return true;
+}
+
+CStdString CGUISpinControl::GetDescription() const
+{
+ CStdString strLabel;
+ strLabel.Format("%i/%i", 1 + GetValue(), GetMaximum());
+ return strLabel;
+}
+
+bool CGUISpinControl::IsFocusedOnUp() const
+{
+ return (m_iSelect == SPIN_BUTTON_UP);
+}
+
+void CGUISpinControl::ChangePage(int amount)
+{
+ m_currentItem += amount * m_itemsPerPage;
+ if (m_currentItem > m_numItems - m_itemsPerPage)
+ m_currentItem = m_numItems - m_itemsPerPage;
+ if (m_currentItem < 0)
+ m_currentItem = 0;
+ CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetParentID(), GetID(), GUI_MSG_PAGE_CHANGE, m_currentItem);
+ SendWindowMessage(message);
+}
+
+void CGUISpinControl::UpdateColors()
+{
+ m_label.UpdateColors();
+ CGUIControl::UpdateColors();
+ m_imgspinDownFocus.SetDiffuseColor(m_diffuseColor);
+ m_imgspinDown.SetDiffuseColor(m_diffuseColor);
+ m_imgspinUp.SetDiffuseColor(m_diffuseColor);
+ m_imgspinUpFocus.SetDiffuseColor(m_diffuseColor);
+}
+
+bool CGUISpinControl::IsVisible() const
+{
+ // page controls can be optionally disabled if the number of pages is 1
+ if (m_iType == SPIN_CONTROL_TYPE_PAGE && m_numItems <= m_itemsPerPage && !m_showOnePage)
+ return false;
+ return CGUIControl::IsVisible();
+}
diff --git a/guilib/GUISpinControl.h b/guilib/GUISpinControl.h
new file mode 100644
index 0000000000..67ea5956c4
--- /dev/null
+++ b/guilib/GUISpinControl.h
@@ -0,0 +1,127 @@
+/*!
+\file GUISpinControl.h
+\brief
+*/
+
+#ifndef GUILIB_SPINCONTROL_H
+#define GUILIB_SPINCONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+#include "GUITexture.h"
+#include "GUITextLayout.h"
+
+#define SPIN_CONTROL_TYPE_INT 1
+#define SPIN_CONTROL_TYPE_FLOAT 2
+#define SPIN_CONTROL_TYPE_TEXT 3
+#define SPIN_CONTROL_TYPE_PAGE 4
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUISpinControl : public CGUIControl
+{
+public:
+ CGUISpinControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& textureUp, const CTextureInfo& textureDown, const CTextureInfo& textureUpFocus, const CTextureInfo& textureDownFocus, const CLabelInfo& labelInfo, int iType);
+ virtual ~CGUISpinControl(void);
+ virtual CGUISpinControl *Clone() const { return new CGUISpinControl(*this); };
+
+ virtual void Render();
+ virtual bool OnAction(const CAction &action);
+ virtual void OnLeft();
+ virtual void OnRight();
+ virtual bool HitTest(const CPoint &point) const;
+ virtual bool OnMouseOver(const CPoint &point);
+ virtual bool OnMouseClick(int button, const CPoint &point);
+ virtual bool OnMouseWheel(char wheel, const CPoint &point);
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual void SetPosition(float posX, float posY);
+ virtual float GetWidth() const;
+ void SetRange(int iStart, int iEnd);
+ void SetFloatRange(float fStart, float fEnd);
+ void SetValue(int iValue);
+ void SetValueFromLabel(const CStdString &label);
+ void SetFloatValue(float fValue);
+ int GetValue() const;
+ float GetFloatValue() const;
+ void AddLabel(const std::string& strLabel, int iValue);
+ const std::string GetLabel() const;
+ void SetReverse(bool bOnOff);
+ int GetMaximum() const;
+ int GetMinimum() const;
+ void SetSpinAlign(uint32_t align, float offsetX) { m_label.align = align; m_label.offsetX = offsetX; };
+ void SetType(int iType) { m_iType = iType; };
+ float GetSpinWidth() const { return m_imgspinUp.GetWidth(); };
+ float GetSpinHeight() const { return m_imgspinUp.GetHeight(); };
+ void SetFloatInterval(float fInterval);
+ void SetShowRange(bool bOnoff) ;
+ void SetShowOnePage(bool showOnePage) { m_showOnePage = showOnePage; };
+ void Clear();
+ virtual CStdString GetDescription() const;
+ bool IsFocusedOnUp() const;
+
+ virtual bool IsVisible() const;
+
+protected:
+ virtual void UpdateColors();
+ void PageUp();
+ void PageDown();
+ bool CanMoveDown(bool bTestReverse = true);
+ bool CanMoveUp(bool bTestReverse = true);
+ void MoveUp(bool bTestReverse = true);
+ void MoveDown(bool bTestReverse = true);
+ void ChangePage(int amount);
+ int m_iStart;
+ int m_iEnd;
+ float m_fStart;
+ float m_fEnd;
+ int m_iValue;
+ float m_fValue;
+ int m_iType;
+ int m_iSelect;
+ bool m_bReverse;
+ float m_fInterval;
+ std::vector<std::string> m_vecLabels;
+ std::vector<int> m_vecValues;
+ CGUITexture m_imgspinUp;
+ CGUITexture m_imgspinDown;
+ CGUITexture m_imgspinUpFocus;
+ CGUITexture m_imgspinDownFocus;
+ CGUITextLayout m_textLayout;
+ CLabelInfo m_label;
+ bool m_bShowRange;
+ char m_szTyped[10];
+ int m_iTypedPos;
+
+ int m_currentItem;
+ int m_itemsPerPage;
+ int m_numItems;
+ bool m_showOnePage;
+};
+#endif
diff --git a/guilib/GUISpinControlEx.cpp b/guilib/GUISpinControlEx.cpp
new file mode 100644
index 0000000000..8c9517cf0e
--- /dev/null
+++ b/guilib/GUISpinControlEx.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUISpinControlEx.h"
+
+CGUISpinControlEx::CGUISpinControlEx(int parentID, int controlID, float posX, float posY, float width, float height, float spinWidth, float spinHeight, const CLabelInfo& spinInfo, const CTextureInfo &textureFocus, const CTextureInfo &textureNoFocus, const CTextureInfo& textureUp, const CTextureInfo& textureDown, const CTextureInfo& textureUpFocus, const CTextureInfo& textureDownFocus, const CLabelInfo& labelInfo, int iType)
+ : CGUISpinControl(parentID, controlID, posX, posY, spinWidth, spinHeight, textureUp, textureDown, textureUpFocus, textureDownFocus, spinInfo, iType)
+ , m_buttonControl(parentID, controlID, posX, posY, width, height, textureFocus, textureNoFocus, labelInfo)
+{
+ ControlType = GUICONTROL_SPINEX;
+ m_spinPosX = 0;
+}
+
+CGUISpinControlEx::~CGUISpinControlEx(void)
+{
+}
+
+void CGUISpinControlEx::AllocResources()
+{
+ // Correct alignment - we always align the spincontrol on the right,
+ // and we always use a negative offsetX
+ m_label.align = (m_label.align & 4) | XBFONT_RIGHT;
+ if (m_label.offsetX > 0)
+ m_label.offsetX = -m_label.offsetX;
+ CGUISpinControl::AllocResources();
+ m_buttonControl.AllocResources();
+ if (m_height == 0)
+ m_height = GetSpinHeight();
+}
+
+void CGUISpinControlEx::FreeResources()
+{
+ CGUISpinControl::FreeResources();
+ m_buttonControl.FreeResources();
+}
+
+void CGUISpinControlEx::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUISpinControl::DynamicResourceAlloc(bOnOff);
+ m_buttonControl.DynamicResourceAlloc(bOnOff);
+}
+
+void CGUISpinControlEx::Render()
+{
+ // make sure the button has focus if it should have...
+ m_buttonControl.SetFocus(HasFocus());
+ m_buttonControl.SetPulseOnSelect(m_pulseOnSelect);
+ m_buttonControl.Render();
+ if (m_bInvalidated)
+ SetPosition(GetXPosition(), GetYPosition());
+
+ CGUISpinControl::Render();
+}
+
+void CGUISpinControlEx::SetPosition(float posX, float posY)
+{
+ m_buttonControl.SetPosition(posX, posY);
+ float spinPosX = posX + m_buttonControl.GetWidth() - GetSpinWidth() * 2 - (m_spinPosX ? m_spinPosX : m_buttonControl.GetLabelInfo().offsetX);
+ float spinPosY = posY + (m_buttonControl.GetHeight() - GetSpinHeight()) * 0.5f;
+ CGUISpinControl::SetPosition(spinPosX, spinPosY);
+}
+
+void CGUISpinControlEx::SetWidth(float width)
+{
+ m_buttonControl.SetWidth(width);
+ SetPosition(m_buttonControl.GetXPosition(), m_buttonControl.GetYPosition());
+}
+
+void CGUISpinControlEx::SetHeight(float height)
+{
+ m_buttonControl.SetHeight(height);
+ SetPosition(m_buttonControl.GetXPosition(), m_buttonControl.GetYPosition());
+}
+
+void CGUISpinControlEx::SetVisible(bool bVisible)
+{
+ m_buttonControl.SetVisible(bVisible);
+ CGUISpinControl::SetVisible(bVisible);
+}
+
+void CGUISpinControlEx::UpdateColors()
+{
+ CGUISpinControl::UpdateColors();
+ m_buttonControl.SetColorDiffuse(m_diffuseColor);
+ m_buttonControl.UpdateColors();
+}
+
+void CGUISpinControlEx::SetEnabled(bool bEnable)
+{
+ m_buttonControl.SetEnabled(bEnable);
+ CGUISpinControl::SetEnabled(bEnable);
+}
+
+const CStdString CGUISpinControlEx::GetCurrentLabel() const
+{
+ return CGUISpinControl::GetLabel();
+}
+
+CStdString CGUISpinControlEx::GetDescription() const
+{
+ CStdString strLabel;
+ strLabel.Format("%s (%s)", m_buttonControl.GetDescription(), GetLabel());
+ return strLabel;
+}
+
+void CGUISpinControlEx::SettingsCategorySetSpinTextColor(const CGUIInfoColor &color)
+{
+ m_label.textColor = color;
+ m_label.focusedColor = color;
+}
+
+void CGUISpinControlEx::SetSpinPosition(float spinPosX)
+{
+ m_spinPosX = spinPosX;
+ SetPosition(m_buttonControl.GetXPosition(), m_buttonControl.GetYPosition());
+}
diff --git a/guilib/GUISpinControlEx.h b/guilib/GUISpinControlEx.h
new file mode 100644
index 0000000000..f82f07e599
--- /dev/null
+++ b/guilib/GUISpinControlEx.h
@@ -0,0 +1,72 @@
+/*!
+\file GUISpinControlEx.h
+\brief
+*/
+
+#ifndef GUILIB_SPINCONTROLEX_H
+#define GUILIB_SPINCONTROLEX_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUISpinControl.h"
+#include "GUIButtonControl.h"
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUISpinControlEx : public CGUISpinControl
+{
+public:
+ CGUISpinControlEx(int parentID, int controlID, float posX, float posY, float width, float height, float spinWidth, float spinHeight, const CLabelInfo& spinInfo, const CTextureInfo &textureFocus, const CTextureInfo &textureNoFocus, const CTextureInfo& textureUp, const CTextureInfo& textureDown, const CTextureInfo& textureUpFocus, const CTextureInfo& textureDownFocus, const CLabelInfo& labelInfo, int iType);
+ virtual ~CGUISpinControlEx(void);
+ virtual CGUISpinControlEx *Clone() const { return new CGUISpinControlEx(*this); };
+
+ virtual void Render();
+ virtual void SetPosition(float posX, float posY);
+ virtual float GetWidth() const { return m_buttonControl.GetWidth();};
+ virtual void SetWidth(float width);
+ virtual float GetHeight() const { return m_buttonControl.GetHeight();};
+ virtual void SetHeight(float height);
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ const CStdString GetCurrentLabel() const;
+ void SetText(const std::string & aLabel) {m_buttonControl.SetLabel(aLabel);};
+ virtual void SetVisible(bool bVisible);
+ const CLabelInfo& GetButtonLabelInfo() { return m_buttonControl.GetLabelInfo(); };
+ virtual void SetEnabled(bool bEnable);
+ virtual float GetXPosition() const { return m_buttonControl.GetXPosition();};
+ virtual float GetYPosition() const { return m_buttonControl.GetYPosition();};
+ virtual CStdString GetDescription() const;
+ virtual bool HitTest(const CPoint &point) const { return m_buttonControl.HitTest(point); };
+ void SetSpinPosition(float spinPosX);
+
+ void SettingsCategorySetSpinTextColor(const CGUIInfoColor &color);
+protected:
+ virtual void UpdateColors();
+ CGUIButtonControl m_buttonControl;
+ float m_spinPosX;
+};
+#endif
diff --git a/guilib/GUIStandardWindow.cpp b/guilib/GUIStandardWindow.cpp
new file mode 100644
index 0000000000..971a9cee9a
--- /dev/null
+++ b/guilib/GUIStandardWindow.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIStandardWindow.h"
+#include "GUIWindowManager.h"
+#include "AdvancedSettings.h"
+#include "Key.h"
+
+CGUIStandardWindow::CGUIStandardWindow(void) : CGUIWindow(0, "")
+{
+}
+
+CGUIStandardWindow::~CGUIStandardWindow(void)
+{
+}
+
+bool CGUIStandardWindow::OnAction(const CAction &action)
+{
+ if (action.id == ACTION_PREVIOUS_MENU)
+ {
+ m_gWindowManager.PreviousWindow();
+ return true;
+ }
+
+ if (action.id == ACTION_PARENT_DIR && g_advancedSettings.m_bUseEvilB)
+ {
+ m_gWindowManager.PreviousWindow();
+ return true;
+ }
+
+ return CGUIWindow::OnAction(action);
+}
diff --git a/guilib/GUIStandardWindow.h b/guilib/GUIStandardWindow.h
new file mode 100644
index 0000000000..94e57b5fc5
--- /dev/null
+++ b/guilib/GUIStandardWindow.h
@@ -0,0 +1,39 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIWindow.h"
+
+// This class is designed to be the base class for any standard
+// full screen window. Default implementations for action keys
+// can be placed into this class to make creating new window
+// classes that much easier.
+
+class CGUIStandardWindow :
+ public CGUIWindow
+{
+public:
+ CGUIStandardWindow(void);
+ virtual ~CGUIStandardWindow(void);
+
+ virtual bool OnAction(const CAction &action);
+};
diff --git a/guilib/GUITextBox.cpp b/guilib/GUITextBox.cpp
new file mode 100644
index 0000000000..b424af6f15
--- /dev/null
+++ b/guilib/GUITextBox.cpp
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUITextBox.h"
+#include "utils/CharsetConverter.h"
+#include "utils/GUIInfoManager.h"
+#include "tinyXML/tinyxml.h"
+
+using namespace std;
+
+CGUITextBox::CGUITextBox(int parentID, int controlID, float posX, float posY, float width, float height,
+ const CLabelInfo& labelInfo, int scrollTime)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+ , CGUITextLayout(labelInfo.font, true)
+{
+ m_offset = 0;
+ m_scrollOffset = 0;
+ m_scrollSpeed = 0;
+ m_itemsPerPage = 10;
+ m_itemHeight = 10;
+ ControlType = GUICONTROL_TEXTBOX;
+ m_pageControl = 0;
+ m_renderTime = 0;
+ m_lastRenderTime = 0;
+ m_scrollTime = scrollTime;
+ m_autoScrollCondition = 0;
+ m_autoScrollTime = 0;
+ m_autoScrollDelay = 3000;
+ m_autoScrollDelayTime = 0;
+ m_autoScrollRepeatAnim = NULL;
+ m_label = labelInfo;
+}
+
+CGUITextBox::CGUITextBox(const CGUITextBox &from)
+: CGUIControl(from), CGUITextLayout(from)
+{
+ m_pageControl = from.m_pageControl;
+ m_scrollTime = from.m_scrollTime;
+ m_autoScrollCondition = from.m_autoScrollCondition;
+ m_autoScrollTime = from.m_autoScrollTime;
+ m_autoScrollDelay = from.m_autoScrollDelay;
+ m_autoScrollRepeatAnim = NULL;
+ m_label = from.m_label;
+ m_info = from.m_info;
+ // defaults
+ m_offset = 0;
+ m_scrollOffset = 0;
+ m_scrollSpeed = 0;
+ m_itemsPerPage = 10;
+ m_itemHeight = 10;
+ m_renderTime = 0;
+ m_lastRenderTime = 0;
+ m_autoScrollDelayTime = 0;
+ ControlType = GUICONTROL_TEXTBOX;
+}
+
+CGUITextBox::~CGUITextBox(void)
+{
+ delete m_autoScrollRepeatAnim;
+ m_autoScrollRepeatAnim = NULL;
+}
+
+void CGUITextBox::DoRender(DWORD currentTime)
+{
+ m_renderTime = currentTime;
+
+ // render the repeat anim as appropriate
+ if (m_autoScrollRepeatAnim)
+ {
+ m_autoScrollRepeatAnim->Animate(m_renderTime, true);
+ TransformMatrix matrix;
+ m_autoScrollRepeatAnim->RenderAnimation(matrix);
+ g_graphicsContext.AddTransform(matrix);
+ }
+
+ CGUIControl::DoRender(currentTime);
+ // if not visible, we reset the autoscroll timer and positioning
+ if (!IsVisible() && m_autoScrollTime)
+ {
+ ResetAutoScrolling();
+ m_lastRenderTime = 0;
+ m_offset = 0;
+ m_scrollOffset = 0;
+ m_scrollSpeed = 0;
+ }
+ if (m_autoScrollRepeatAnim)
+ g_graphicsContext.RemoveTransform();
+}
+
+void CGUITextBox::UpdateColors()
+{
+ m_label.UpdateColors();
+ CGUIControl::UpdateColors();
+}
+
+void CGUITextBox::UpdateInfo(const CGUIListItem *item)
+{
+ m_textColor = m_label.textColor;
+ if (!CGUITextLayout::Update(item ? m_info.GetItemLabel(item) : m_info.GetLabel(m_parentID), m_width))
+ return; // nothing changed
+
+ // needed update, so reset to the top of the textbox and update our sizing/page control
+ m_offset = 0;
+ m_scrollOffset = 0;
+ ResetAutoScrolling();
+
+ m_itemHeight = m_font->GetLineHeight();
+ m_itemsPerPage = (unsigned int)(m_height / m_itemHeight);
+
+ UpdatePageControl();
+}
+
+void CGUITextBox::Render()
+{
+ // update our auto-scrolling as necessary
+ if (m_autoScrollTime && m_lines.size() > m_itemsPerPage)
+ {
+ if (!m_autoScrollCondition || g_infoManager.GetBool(m_autoScrollCondition, m_parentID))
+ {
+ if (m_lastRenderTime)
+ m_autoScrollDelayTime += m_renderTime - m_lastRenderTime;
+ if (m_autoScrollDelayTime > (unsigned int)m_autoScrollDelay && m_scrollSpeed == 0)
+ { // delay is finished - start scrolling
+ if (m_offset < (int)m_lines.size() - m_itemsPerPage)
+ ScrollToOffset(m_offset + 1, true);
+ else
+ { // at the end, run a delay and restart
+ if (m_autoScrollRepeatAnim)
+ {
+ if (m_autoScrollRepeatAnim->GetState() == ANIM_STATE_NONE)
+ m_autoScrollRepeatAnim->QueueAnimation(ANIM_PROCESS_NORMAL);
+ else if (m_autoScrollRepeatAnim->GetState() == ANIM_STATE_APPLIED)
+ { // reset to the start of the list and start the scrolling again
+ m_offset = 0;
+ m_scrollOffset = 0;
+ ResetAutoScrolling();
+ }
+ }
+ }
+ }
+ }
+ else if (m_autoScrollCondition)
+ ResetAutoScrolling(); // conditional is false, so reset the autoscrolling
+ }
+
+ // update our scroll position as necessary
+ if (m_lastRenderTime)
+ m_scrollOffset += m_scrollSpeed * (m_renderTime - m_lastRenderTime);
+ if ((m_scrollSpeed < 0 && m_scrollOffset < m_offset * m_itemHeight) ||
+ (m_scrollSpeed > 0 && m_scrollOffset > m_offset * m_itemHeight))
+ {
+ m_scrollOffset = m_offset * m_itemHeight;
+ m_scrollSpeed = 0;
+ }
+ m_lastRenderTime = m_renderTime;
+
+ int offset = (int)(m_scrollOffset / m_itemHeight);
+
+ g_graphicsContext.SetClipRegion(m_posX, m_posY, m_width, m_height);
+
+ // we offset our draw position to take into account scrolling and whether or not our focused
+ // item is offscreen "above" the list.
+ float posX = m_posX;
+ float posY = m_posY + offset * m_itemHeight - m_scrollOffset;
+
+ // alignment correction
+ if (m_label.align & XBFONT_CENTER_X)
+ posX += m_width * 0.5f;
+ if (m_label.align & XBFONT_RIGHT)
+ posX += m_width;
+
+ if (m_font)
+ {
+ m_font->Begin();
+ int current = offset;
+ while (posY < m_posY + m_height && current < (int)m_lines.size())
+ {
+ uint32_t align = m_label.align;
+ if (m_lines[current].m_text.size() && m_lines[current].m_carriageReturn)
+ align &= ~XBFONT_JUSTIFIED; // last line of a paragraph shouldn't be justified
+ m_font->DrawText(posX, posY + 2, m_colors, m_label.shadowColor, m_lines[current].m_text, align, m_width);
+ posY += m_itemHeight;
+ current++;
+ }
+ m_font->End();
+ }
+
+ g_graphicsContext.RestoreClipRegion();
+
+ if (m_pageControl)
+ {
+ CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), m_pageControl, offset);
+ SendWindowMessage(msg);
+ }
+ CGUIControl::Render();
+}
+
+bool CGUITextBox::OnMessage(CGUIMessage& message)
+{
+ if (message.GetControlId() == GetID())
+ {
+ if (message.GetMessage() == GUI_MSG_LABEL_SET)
+ {
+ m_offset = 0;
+ m_scrollOffset = 0;
+ ResetAutoScrolling();
+ CGUITextLayout::Reset();
+ m_info.SetLabel(message.GetLabel(), "");
+ }
+
+ if (message.GetMessage() == GUI_MSG_LABEL_RESET)
+ {
+ m_offset = 0;
+ m_scrollOffset = 0;
+ ResetAutoScrolling();
+ CGUITextLayout::Reset();
+ if (m_pageControl)
+ {
+ CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), m_pageControl, m_itemsPerPage, m_lines.size());
+ SendWindowMessage(msg);
+ }
+ }
+
+ if (message.GetMessage() == GUI_MSG_PAGE_CHANGE)
+ {
+ if (message.GetSenderId() == m_pageControl)
+ { // update our page
+ Scroll(message.GetParam1());
+ return true;
+ }
+ }
+ }
+
+ return CGUIControl::OnMessage(message);
+}
+
+void CGUITextBox::UpdatePageControl()
+{
+ if (m_pageControl)
+ {
+ CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), m_pageControl, m_itemsPerPage, m_lines.size());
+ SendWindowMessage(msg);
+ }
+}
+
+bool CGUITextBox::CanFocus() const
+{
+ return false;
+}
+
+void CGUITextBox::SetPageControl(int pageControl)
+{
+ m_pageControl = pageControl;
+}
+
+void CGUITextBox::SetInfo(const CGUIInfoLabel &infoLabel)
+{
+ m_info = infoLabel;
+}
+
+void CGUITextBox::Scroll(unsigned int offset)
+{
+ ResetAutoScrolling();
+ if (m_lines.size() <= m_itemsPerPage)
+ return; // no need to scroll
+ if (offset > m_lines.size() - m_itemsPerPage)
+ offset = m_lines.size() - m_itemsPerPage; // on last page
+ ScrollToOffset(offset);
+}
+
+void CGUITextBox::ScrollToOffset(int offset, bool autoScroll)
+{
+ m_scrollOffset = m_offset * m_itemHeight;
+ int timeToScroll = autoScroll ? m_autoScrollTime : m_scrollTime;
+ m_scrollSpeed = (offset * m_itemHeight - m_scrollOffset) / timeToScroll;
+ m_offset = offset;
+}
+
+void CGUITextBox::SetAutoScrolling(const TiXmlNode *node)
+{
+ if (!node) return;
+ const TiXmlElement *scroll = node->FirstChildElement("autoscroll");
+ if (scroll)
+ {
+ scroll->Attribute("delay", &m_autoScrollDelay);
+ scroll->Attribute("time", &m_autoScrollTime);
+ if (scroll->FirstChild())
+ m_autoScrollCondition = g_infoManager.TranslateString(scroll->FirstChild()->ValueStr());
+ int repeatTime;
+ if (scroll->Attribute("repeat", &repeatTime))
+ m_autoScrollRepeatAnim = CAnimation::CreateFader(100, 0, repeatTime, 1000);
+ }
+}
+
+void CGUITextBox::ResetAutoScrolling()
+{
+ m_autoScrollDelayTime = 0;
+ if (m_autoScrollRepeatAnim)
+ m_autoScrollRepeatAnim->ResetAnimation();
+}
+
+unsigned int CGUITextBox::GetRows() const
+{
+ return m_lines.size();
+}
+
+int CGUITextBox::GetCurrentPage() const
+{
+ if (m_offset + m_itemsPerPage >= GetRows()) // last page
+ return (GetRows() + m_itemsPerPage - 1) / m_itemsPerPage;
+ return m_offset / m_itemsPerPage + 1;
+}
+
+CStdString CGUITextBox::GetLabel(int info) const
+{
+ CStdString label;
+ switch (info)
+ {
+ case CONTAINER_NUM_PAGES:
+ label.Format("%u", (GetRows() + m_itemsPerPage - 1) / m_itemsPerPage);
+ break;
+ case CONTAINER_CURRENT_PAGE:
+ label.Format("%u", GetCurrentPage());
+ break;
+ default:
+ break;
+ }
+ return label;
+}
diff --git a/guilib/GUITextBox.h b/guilib/GUITextBox.h
new file mode 100644
index 0000000000..c4ab36eef4
--- /dev/null
+++ b/guilib/GUITextBox.h
@@ -0,0 +1,96 @@
+/*!
+\file GUITextBox.h
+\brief
+*/
+
+#ifndef GUILIB_GUITEXTBOX_H
+#define GUILIB_GUITEXTBOX_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUILabelControl.h"
+#include "GUITextLayout.h"
+
+/*!
+ \ingroup controls
+ \brief
+ */
+
+class TiXmlNode;
+
+class CGUITextBox : public CGUIControl, public CGUITextLayout
+{
+public:
+ CGUITextBox(int parentID, int controlID, float posX, float posY, float width, float height,
+ const CLabelInfo &labelInfo, int scrollTime = 200);
+ CGUITextBox(const CGUITextBox &from);
+ virtual ~CGUITextBox(void);
+ virtual CGUITextBox *Clone() const { return new CGUITextBox(*this); };
+
+ virtual void DoRender(DWORD currentTime);
+ virtual void Render();
+ virtual bool OnMessage(CGUIMessage& message);
+
+ void SetPageControl(int pageControl);
+
+ virtual bool CanFocus() const;
+ void SetInfo(const CGUIInfoLabel &info);
+ void SetAutoScrolling(const TiXmlNode *node);
+ void ResetAutoScrolling();
+ CStdString GetLabel(int info) const;
+
+ void Scroll(unsigned int offset);
+
+protected:
+ virtual void UpdateColors();
+ virtual void UpdateInfo(const CGUIListItem *item = NULL);
+ void UpdatePageControl();
+ void ScrollToOffset(int offset, bool autoScroll = false);
+ unsigned int GetRows() const;
+ int GetCurrentPage() const;
+
+ // offset of text in the control for scrolling
+ unsigned int m_offset;
+ float m_scrollOffset;
+ float m_scrollSpeed;
+ int m_scrollTime;
+ unsigned int m_itemsPerPage;
+ float m_itemHeight;
+ DWORD m_renderTime;
+ DWORD m_lastRenderTime;
+
+ CLabelInfo m_label;
+
+ // autoscrolling
+ int m_autoScrollCondition;
+ int m_autoScrollTime; // time to scroll 1 line (ms)
+ int m_autoScrollDelay; // delay before scroll (ms)
+ DWORD m_autoScrollDelayTime; // current offset into the delay
+ CAnimation *m_autoScrollRepeatAnim;
+
+ int m_pageControl;
+
+ CGUIInfoLabel m_info;
+};
+#endif
diff --git a/guilib/GUITextLayout.cpp b/guilib/GUITextLayout.cpp
new file mode 100644
index 0000000000..b283080dfb
--- /dev/null
+++ b/guilib/GUITextLayout.cpp
@@ -0,0 +1,635 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUITextLayout.h"
+#include "GUIFont.h"
+#include "GUIControl.h"
+#include "GUIColorManager.h"
+#include "utils/CharsetConverter.h"
+#include "StringUtils.h"
+
+using namespace std;
+
+#define WORK_AROUND_NEEDED_FOR_LINE_BREAKS
+
+CGUIString::CGUIString(iString start, iString end, bool carriageReturn)
+{
+ m_text.assign(start, end);
+ m_carriageReturn = carriageReturn;
+}
+
+CStdString CGUIString::GetAsString() const
+{
+ CStdString text;
+ for (unsigned int i = 0; i < m_text.size(); i++)
+ text += (char)(m_text[i] & 0xff);
+ return text;
+}
+
+CGUITextLayout::CGUITextLayout(CGUIFont *font, bool wrap, float fHeight)
+{
+ m_font = font;
+ m_textColor = 0;
+ m_wrap = wrap;
+ m_maxHeight = fHeight;
+ m_textWidth = 0;
+ m_textHeight = 0;
+}
+
+void CGUITextLayout::SetWrap(bool bWrap)
+{
+ m_wrap = bWrap;
+}
+
+void CGUITextLayout::Render(float x, float y, float angle, color_t color, color_t shadowColor, uint32_t alignment, float maxWidth, bool solid)
+{
+ if (!m_font)
+ return;
+
+ // set the main text color
+ if (m_colors.size())
+ m_colors[0] = color;
+
+ // render the text at the required location, angle, and size
+ if (angle)
+ {
+ static const float degrees_to_radians = 0.01745329252f;
+ g_graphicsContext.AddTransform(TransformMatrix::CreateZRotation(angle * degrees_to_radians, x, y, g_graphicsContext.GetScalingPixelRatio()));
+ }
+ // center our text vertically
+ if (alignment & XBFONT_CENTER_Y)
+ {
+ y -= m_font->GetTextHeight(m_lines.size()) * 0.5f;;
+ alignment &= ~XBFONT_CENTER_Y;
+ }
+ m_font->Begin();
+ for (vector<CGUIString>::iterator i = m_lines.begin(); i != m_lines.end(); i++)
+ {
+ const CGUIString &string = *i;
+ uint32_t align = alignment;
+ if (align & XBFONT_JUSTIFIED && string.m_carriageReturn)
+ align &= ~XBFONT_JUSTIFIED;
+ if (solid)
+ m_font->DrawText(x, y, m_colors[0], shadowColor, string.m_text, align, maxWidth);
+ else
+ m_font->DrawText(x, y, m_colors, shadowColor, string.m_text, align, maxWidth);
+ y += m_font->GetLineHeight();
+ }
+ m_font->End();
+ if (angle)
+ g_graphicsContext.RemoveTransform();
+}
+
+
+void CGUITextLayout::RenderScrolling(float x, float y, float angle, color_t color, color_t shadowColor, uint32_t alignment, float maxWidth, CScrollInfo &scrollInfo)
+{
+ if (!m_font)
+ return;
+
+ // set the main text color
+ if (m_colors.size())
+ m_colors[0] = color;
+
+ // render the text at the required location, angle, and size
+ if (angle)
+ {
+ static const float degrees_to_radians = 0.01745329252f;
+ g_graphicsContext.AddTransform(TransformMatrix::CreateZRotation(angle * degrees_to_radians, x, y, g_graphicsContext.GetScalingPixelRatio()));
+ }
+ // center our text vertically
+ if (alignment & XBFONT_CENTER_Y)
+ {
+ y -= m_font->GetTextHeight(m_lines.size()) * 0.5f;;
+ alignment &= ~XBFONT_CENTER_Y;
+ }
+ m_font->Begin();
+ // NOTE: This workaround is needed as otherwise multi-line text that scrolls
+ // will scroll in proportion to the number of lines. Ideally we should
+ // do the DrawScrollingText calculation here. This probably won't make
+ // any difference to the smoothness of scrolling though which will be
+ // jumpy with this sort of thing. It's not exactly a well used situation
+ // though, so this hack is probably OK.
+ float speed = scrollInfo.pixelSpeed;
+ for (vector<CGUIString>::iterator i = m_lines.begin(); i != m_lines.end(); i++)
+ {
+ const CGUIString &string = *i;
+ m_font->DrawScrollingText(x, y, m_colors, shadowColor, string.m_text, alignment, maxWidth, scrollInfo);
+ y += m_font->GetLineHeight();
+ scrollInfo.pixelSpeed = 0;
+ }
+ scrollInfo.pixelSpeed = speed;
+ m_font->End();
+ if (angle)
+ g_graphicsContext.RemoveTransform();
+}
+
+void CGUITextLayout::RenderOutline(float x, float y, color_t color, color_t outlineColor, uint32_t outlineWidth, uint32_t alignment, float maxWidth)
+{
+ if (!m_font)
+ return;
+
+ // set the main text color
+ if (m_colors.size())
+ m_colors[0] = color;
+
+ // center our text vertically
+ if (alignment & XBFONT_CENTER_Y)
+ {
+ y -= m_font->GetTextHeight(m_lines.size()) * 0.5f;;
+ alignment &= ~XBFONT_CENTER_Y;
+ }
+ m_font->Begin();
+ for (vector<CGUIString>::iterator i = m_lines.begin(); i != m_lines.end(); i++)
+ {
+ const CGUIString &string = *i;
+ uint32_t align = alignment;
+ if (align & XBFONT_JUSTIFIED && string.m_carriageReturn)
+ align &= ~XBFONT_JUSTIFIED;
+
+ DrawOutlineText(m_font, x, y, m_colors, outlineColor, outlineWidth, string.m_text, align, maxWidth);
+ y += m_font->GetLineHeight();
+ }
+ m_font->End();
+}
+
+bool CGUITextLayout::Update(const CStdString &text, float maxWidth, bool forceUpdate /*= false*/, bool forceLTRReadingOrder /*= false*/)
+{
+ if (text == m_lastText && !forceUpdate)
+ return false;
+
+ // convert to utf16
+ CStdStringW utf16;
+ utf8ToW(text, utf16);
+
+ // update
+ SetText(utf16, maxWidth, forceLTRReadingOrder);
+
+ // and set our parameters to indicate no further update is required
+ m_lastText = text;
+ return true;
+}
+
+void CGUITextLayout::SetText(const CStdStringW &text, float maxWidth, bool forceLTRReadingOrder /*= false*/)
+{
+ vecText parsedText;
+
+ // empty out our previous string
+ m_lines.clear();
+ m_colors.clear();
+ m_colors.push_back(m_textColor);
+
+ // parse the text into our string objects
+ ParseText(text, parsedText);
+
+ // add \n to the end of the string
+ parsedText.push_back(L'\n');
+
+ // if we need to wrap the text, then do so
+ if (m_wrap && maxWidth > 0)
+ WrapText(parsedText, maxWidth);
+ else
+ LineBreakText(parsedText, m_lines);
+
+ // remove any trailing blank lines
+ while (!m_lines.empty() && m_lines.back().m_text.empty())
+ m_lines.pop_back();
+
+ BidiTransform(m_lines, forceLTRReadingOrder);
+
+ // and cache the width and height for later reading
+ CalcTextExtent();
+}
+
+// BidiTransform is used to handle RTL text flipping in the string
+void CGUITextLayout::BidiTransform(vector<CGUIString> &lines, bool forceLTRReadingOrder)
+{
+ for (unsigned int i=0; i<lines.size(); i++)
+ {
+ CGUIString &line = lines[i];
+
+ // reserve enough space in the flipped text
+ vecText flippedText;
+ flippedText.reserve(line.m_text.size());
+
+ character_t sectionStyle = 0xffff0000; // impossible to achieve
+ CStdStringW sectionText;
+ for (vecText::iterator it = line.m_text.begin(); it != line.m_text.end(); ++it)
+ {
+ character_t style = *it & 0xffff0000;
+ if (style != sectionStyle)
+ {
+ if (!sectionText.IsEmpty())
+ { // style has changed, bidi flip text
+ CStdStringW sectionFlipped = BidiFlip(sectionText, forceLTRReadingOrder);
+ for (unsigned int j = 0; j < sectionFlipped.size(); j++)
+ flippedText.push_back(sectionStyle | sectionFlipped[j]);
+ }
+ sectionStyle = style;
+ sectionText.clear();
+ }
+ sectionText.push_back( (wchar_t)(*it & 0xffff) );
+ }
+
+ // handle the last section
+ if (!sectionText.IsEmpty())
+ {
+ CStdStringW sectionFlipped = BidiFlip(sectionText, forceLTRReadingOrder);
+ for (unsigned int j = 0; j < sectionFlipped.size(); j++)
+ flippedText.push_back(sectionStyle | sectionFlipped[j]);
+ }
+
+ // replace the original line with the proccessed one
+ lines[i] = CGUIString(flippedText.begin(), flippedText.end(), line.m_carriageReturn);
+ }
+}
+
+CStdStringW CGUITextLayout::BidiFlip(const CStdStringW &text, bool forceLTRReadingOrder)
+{
+ CStdStringA utf8text;
+ CStdStringW visualText;
+
+ // convert to utf8, and back to utf16 with bidi flipping
+ g_charsetConverter.wToUTF8(text, utf8text);
+ g_charsetConverter.utf8ToW(utf8text, visualText, true, forceLTRReadingOrder);
+
+ return visualText;
+}
+
+void CGUITextLayout::Filter(CStdString &text)
+{
+ CStdStringW utf16;
+ utf8ToW(text, utf16);
+ vecColors colors;
+ vecText parsedText;
+ ParseText(utf16, 0, colors, parsedText);
+ utf16.Empty();
+ for (unsigned int i = 0; i < parsedText.size(); i++)
+ utf16 += (wchar_t)(0xffff & parsedText[i]);
+ g_charsetConverter.wToUTF8(utf16, text);
+}
+
+void CGUITextLayout::ParseText(const CStdStringW &text, vecText &parsedText)
+{
+ if (!m_font)
+ return;
+ ParseText(text, m_font->GetStyle(), m_colors, parsedText);
+}
+
+void CGUITextLayout::ParseText(const CStdStringW &text, uint32_t defaultStyle, vecColors &colors, vecText &parsedText)
+{
+ // run through the string, searching for:
+ // [B] or [/B] -> toggle bold on and off
+ // [I] or [/I] -> toggle italics on and off
+ // [COLOR ffab007f] or [/COLOR] -> toggle color on and off
+ // [CAPS <option>] or [/CAPS] -> toggle capatilization on and off
+
+ uint32_t currentStyle = defaultStyle; // start with the default font's style
+ color_t currentColor = 0;
+
+ stack<color_t> colorStack;
+ colorStack.push(0);
+
+ // these aren't independent, but that's probably not too much of an issue
+ // eg [UPPERCASE]Glah[LOWERCASE]FReD[/LOWERCASE]Georeg[/UPPERCASE] will work (lower case >> upper case)
+ // but [LOWERCASE]Glah[UPPERCASE]FReD[/UPPERCASE]Georeg[/LOWERCASE] won't
+#define FONT_STYLE_UPPERCASE 4
+#define FONT_STYLE_LOWERCASE 8
+
+ int startPos = 0;
+ size_t pos = text.Find(L'[');
+ while (pos != CStdString::npos && pos + 1 < text.size())
+ {
+ uint32_t newStyle = 0;
+ color_t newColor = currentColor;
+ bool newLine = false;
+ // have a [ - check if it's an ON or OFF switch
+ bool on(true);
+ int endPos = pos++; // finish of string
+ if (text[pos] == L'/')
+ {
+ on = false;
+ pos++;
+ }
+ // check for each type
+ if (text.Mid(pos,2) == L"B]")
+ { // bold - finish the current text block and assign the bold state
+ pos += 2;
+ if ((on && text.Find(L"[/B]",pos) >= 0) || // check for a matching end point
+ (!on && (currentStyle & FONT_STYLE_BOLD))) // or matching start point
+ newStyle = FONT_STYLE_BOLD;
+ }
+ else if (text.Mid(pos,2) == L"I]")
+ { // italics
+ pos += 2;
+ if ((on && text.Find(L"[/I]",pos) >= 0) || // check for a matching end point
+ (!on && (currentStyle & FONT_STYLE_ITALICS))) // or matching start point
+ newStyle = FONT_STYLE_ITALICS;
+ }
+ else if (text.Mid(pos,10) == L"UPPERCASE]")
+ {
+ pos += 10;
+ if ((on && text.Find(L"[/UPPERCASE]",pos) >= 0) || // check for a matching end point
+ (!on && (currentStyle & FONT_STYLE_UPPERCASE))) // or matching start point
+ newStyle = FONT_STYLE_UPPERCASE;
+ }
+ else if (text.Mid(pos,10) == L"LOWERCASE]")
+ {
+ pos += 10;
+ if ((on && text.Find(L"[/LOWERCASE]",pos) >= 0) || // check for a matching end point
+ (!on && (currentStyle & FONT_STYLE_LOWERCASE))) // or matching start point
+ newStyle = FONT_STYLE_LOWERCASE;
+ }
+ else if (text.Mid(pos,3) == L"CR]" && on)
+ {
+ newLine = true;
+ pos += 3;
+ }
+ else if (text.Mid(pos,5) == L"COLOR")
+ { // color
+ size_t finish = text.Find(L']', pos + 5);
+ if (on && finish != CStdString::npos && (size_t)text.Find(L"[/COLOR]",finish) != CStdString::npos)
+ { // create new color
+ newColor = colors.size();
+ colors.push_back(g_colorManager.GetColor(text.Mid(pos + 5, finish - pos - 5)));
+ colorStack.push(newColor);
+ }
+ else if (!on && finish == pos + 5 && colorStack.size() > 1)
+ { // revert to previous color
+ colorStack.pop();
+ newColor = colorStack.top();
+ }
+ pos = finish + 1;
+ }
+
+ if (newStyle || newColor != currentColor || newLine)
+ { // we have a new style or a new color, so format up the previous segment
+ CStdStringW subText = text.Mid(startPos, endPos - startPos);
+ if (currentStyle & FONT_STYLE_UPPERCASE)
+ subText.ToUpper();
+ if (currentStyle & FONT_STYLE_LOWERCASE)
+ subText.ToLower();
+ AppendToUTF32(subText, ((currentStyle & 3) << 24) | (currentColor << 16), parsedText);
+ if (newLine)
+ parsedText.push_back(L'\n');
+
+ // and switch to the new style
+ startPos = pos;
+ currentColor = newColor;
+ if (on)
+ currentStyle |= newStyle;
+ else
+ currentStyle &= ~newStyle;
+ }
+ pos = text.Find(L'[',pos);
+ }
+ // now grab the remainder of the string
+ CStdStringW subText = text.Mid(startPos, text.GetLength() - startPos);
+ if (currentStyle & FONT_STYLE_UPPERCASE)
+ subText.ToUpper();
+ if (currentStyle & FONT_STYLE_LOWERCASE)
+ subText.ToLower();
+ AppendToUTF32(subText, ((currentStyle & 3) << 24) | (currentColor << 16), parsedText);
+}
+
+void CGUITextLayout::SetMaxHeight(float fHeight)
+{
+ m_maxHeight = fHeight;
+}
+
+void CGUITextLayout::WrapText(const vecText &text, float maxWidth)
+{
+ if (!m_font)
+ return;
+
+ int nMaxLines = (m_maxHeight > 0 && m_font->GetLineHeight() > 0)?(int)(m_maxHeight / m_font->GetLineHeight()):-1;
+
+ m_lines.clear();
+
+ vector<CGUIString> lines;
+ LineBreakText(text, lines);
+
+ for (unsigned int i = 0; i < lines.size(); i++)
+ {
+ const CGUIString &line = lines[i];
+ vecText::const_iterator lastSpace = line.m_text.begin();
+ vecText::const_iterator pos = line.m_text.begin();
+ unsigned int lastSpaceInLine = 0;
+ vecText curLine;
+ while (pos != line.m_text.end() && (nMaxLines <= 0 || m_lines.size() <= (size_t)nMaxLines))
+ {
+ // Get the current letter in the string
+ character_t letter = *pos;
+ // check for a space
+ if (CanWrapAtLetter(letter))
+ {
+ float width = m_font->GetTextWidth(curLine);
+ if (width > maxWidth)
+ {
+ if (lastSpace != line.m_text.begin() && lastSpaceInLine > 0)
+ {
+ CGUIString string(curLine.begin(), curLine.begin() + lastSpaceInLine, false);
+ m_lines.push_back(string);
+ if (IsSpace(letter))
+ lastSpace++; // ignore the space
+ pos = lastSpace;
+ curLine.clear();
+ lastSpaceInLine = 0;
+ lastSpace = line.m_text.begin();
+ continue;
+ }
+ }
+ // only add spaces if we're not empty
+ if (!IsSpace(letter) || curLine.size())
+ {
+ lastSpace = pos;
+ lastSpaceInLine = curLine.size();
+ curLine.push_back(letter);
+ }
+ }
+ else
+ curLine.push_back(letter);
+ pos++;
+ }
+ // now add whatever we have left to the string
+ float width = m_font->GetTextWidth(curLine);
+ if (width > maxWidth)
+ {
+ // too long - put up to the last space on if we can + remove it from what's left.
+ if (lastSpace != line.m_text.begin() && lastSpaceInLine > 0)
+ {
+ CGUIString string(curLine.begin(), curLine.begin() + lastSpaceInLine, false);
+ m_lines.push_back(string);
+ curLine.erase(curLine.begin(), curLine.begin() + lastSpaceInLine);
+ while (curLine.size() && IsSpace(curLine.at(0)))
+ curLine.erase(curLine.begin());
+ }
+ }
+ CGUIString string(curLine.begin(), curLine.end(), true);
+ m_lines.push_back(string);
+ }
+}
+
+void CGUITextLayout::LineBreakText(const vecText &text, vector<CGUIString> &lines)
+{
+ vecText::const_iterator lineStart = text.begin();
+ vecText::const_iterator pos = text.begin();
+ while (pos != text.end())
+ {
+ // Get the current letter in the string
+ character_t letter = *pos;
+
+ // Handle the newline character
+ if ((letter & 0xffff) == L'\n' )
+ { // push back everything up till now
+ CGUIString string(lineStart, pos, true);
+ lines.push_back(string);
+ lineStart = pos + 1;
+ }
+ pos++;
+ }
+}
+
+void CGUITextLayout::GetTextExtent(float &width, float &height) const
+{
+ width = m_textWidth;
+ height = m_textHeight;
+}
+
+void CGUITextLayout::CalcTextExtent()
+{
+ m_textWidth = 0;
+ m_textHeight = 0;
+ if (!m_font) return;
+
+ for (vector<CGUIString>::iterator i = m_lines.begin(); i != m_lines.end(); i++)
+ {
+ const CGUIString &string = *i;
+ float w = m_font->GetTextWidth(string.m_text);
+ if (w > m_textWidth)
+ m_textWidth = w;
+ }
+ m_textHeight = m_font->GetTextHeight(m_lines.size());
+}
+
+unsigned int CGUITextLayout::GetTextLength() const
+{
+ unsigned int length = 0;
+ for (vector<CGUIString>::const_iterator i = m_lines.begin(); i != m_lines.end(); i++)
+ length += i->m_text.size();
+ return length;
+}
+
+void CGUITextLayout::GetFirstText(vecText &text) const
+{
+ text.clear();
+ if (m_lines.size())
+ text = m_lines[0].m_text;
+}
+
+float CGUITextLayout::GetTextWidth(const CStdStringW &text) const
+{
+ // NOTE: Assumes a single line of text
+ if (!m_font) return 0;
+ vecText utf32;
+ AppendToUTF32(text, (m_font->GetStyle() & 3) << 24, utf32);
+ return m_font->GetTextWidth(utf32);
+}
+
+void CGUITextLayout::DrawText(CGUIFont *font, float x, float y, color_t color, color_t shadowColor, const CStdString &text, uint32_t align)
+{
+ if (!font) return;
+ vecText utf32;
+ AppendToUTF32(text, 0, utf32);
+ font->DrawText(x, y, color, shadowColor, utf32, align, 0);
+}
+
+void CGUITextLayout::DrawOutlineText(CGUIFont *font, float x, float y, color_t color, color_t outlineColor, uint32_t outlineWidth, const CStdString &text)
+{
+ if (!font) return;
+ vecText utf32;
+ AppendToUTF32(text, 0, utf32);
+ vecColors colors;
+ colors.push_back(color);
+ DrawOutlineText(font, x, y, colors, outlineColor, outlineWidth, utf32, 0, 0);
+}
+
+void CGUITextLayout::DrawOutlineText(CGUIFont *font, float x, float y, const vecColors &colors, color_t outlineColor, uint32_t outlineWidth, const vecText &text, uint32_t align, float maxWidth)
+{
+ for (unsigned int i = 1; i < outlineWidth; i++)
+ {
+ unsigned int ymax = (unsigned int)(sqrt((float)outlineWidth*outlineWidth - i*i) + 0.5f);
+ for (unsigned int j = 1; j < ymax; j++)
+ {
+ font->DrawText(x - i, y + j, outlineColor, 0, text, align, maxWidth);
+ font->DrawText(x - i, y - j, outlineColor, 0, text, align, maxWidth);
+ font->DrawText(x + i, y + j, outlineColor, 0, text, align, maxWidth);
+ font->DrawText(x + i, y - j, outlineColor, 0, text, align, maxWidth);
+ }
+ }
+ font->DrawText(x, y, colors, 0, text, align, maxWidth);
+}
+
+void CGUITextLayout::AppendToUTF32(const CStdStringW &utf16, character_t colStyle, vecText &utf32)
+{
+ // NOTE: Assumes a single line of text
+ utf32.reserve(utf32.size() + utf16.size());
+ for (unsigned int i = 0; i < utf16.size(); i++)
+ utf32.push_back(utf16[i] | colStyle);
+}
+
+void CGUITextLayout::utf8ToW(const CStdString &utf8, CStdStringW &utf16)
+{
+#ifdef WORK_AROUND_NEEDED_FOR_LINE_BREAKS
+ // NOTE: This appears to strip \n characters from text. This may be a consequence of incorrect
+ // expression of the \n in utf8 (we just use character code 10) or it might be something
+ // more sinister. For now, we use the workaround below.
+ CStdStringArray multiLines;
+ StringUtils::SplitString(utf8, "\n", multiLines);
+ for (unsigned int i = 0; i < multiLines.size(); i++)
+ {
+ CStdStringW line;
+ // no need to bidiflip here - it's done in BidiTransform above
+ g_charsetConverter.utf8ToW(multiLines[i], line, false);
+ utf16 += line;
+ if (i < multiLines.size() - 1)
+ utf16.push_back(L'\n');
+ }
+#else
+ // no need to bidiflip here - it's done in BidiTransform above
+ g_charsetConverter.utf8ToW(utf8, utf16, false);
+#endif
+}
+
+void CGUITextLayout::AppendToUTF32(const CStdString &utf8, character_t colStyle, vecText &utf32)
+{
+ CStdStringW utf16;
+ utf8ToW(utf8, utf16);
+ AppendToUTF32(utf16, colStyle, utf32);
+}
+
+void CGUITextLayout::Reset()
+{
+ m_lines.clear();
+ m_lastText.Empty();
+ m_textWidth = m_textHeight = 0;
+}
+
+
diff --git a/guilib/GUITextLayout.h b/guilib/GUITextLayout.h
new file mode 100644
index 0000000000..2633731637
--- /dev/null
+++ b/guilib/GUITextLayout.h
@@ -0,0 +1,132 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "StdString.h"
+
+#include <vector>
+
+#ifdef __GNUC__
+// under gcc, inline will only take place if optimizations are applied (-O). this will force inline even without optimizations.
+#define XBMC_FORCE_INLINE __attribute__((always_inline))
+#else
+#define XBMC_FORCE_INLINE
+#endif
+
+class CGUIFont;
+class CScrollInfo;
+
+// Process will be:
+
+// 1. String is divided up into a "multiinfo" vector via the infomanager.
+// 2. The multiinfo vector is then parsed by the infomanager at rendertime and the resultant string is constructed.
+// 3. This is saved for comparison perhaps. If the same, we are done. If not, go to 4.
+// 4. The string is then parsed into a vector<CGUIString>.
+// 5. Each item in the vector is length-calculated, and then layout occurs governed by alignment and wrapping rules.
+// 6. A new vector<CGUIString> is constructed
+
+typedef uint32_t character_t;
+typedef uint32_t color_t;
+typedef std::vector<character_t> vecText;
+typedef std::vector<color_t> vecColors;
+
+class CGUIString
+{
+public:
+ typedef vecText::const_iterator iString;
+
+ CGUIString(iString start, iString end, bool carriageReturn);
+
+ CStdString GetAsString() const;
+
+ vecText m_text;
+ bool m_carriageReturn; // true if we have a carriage return here
+};
+
+class CGUITextLayout
+{
+public:
+ CGUITextLayout(CGUIFont *font, bool wrap, float fHeight=0.0f); // this may need changing - we may just use this class to replace CLabelInfo completely
+
+ // main function to render strings
+ void Render(float x, float y, float angle, color_t color, color_t shadowColor, uint32_t alignment, float maxWidth, bool solid = false);
+ void RenderScrolling(float x, float y, float angle, color_t color, color_t shadowColor, uint32_t alignment, float maxWidth, CScrollInfo &scrollInfo);
+ void RenderOutline(float x, float y, color_t color, color_t outlineColor, uint32_t outlineWidth, uint32_t alignment, float maxWidth);
+ void GetTextExtent(float &width, float &height) const;
+ float GetTextWidth() const { return m_textWidth; };
+ float GetTextWidth(const CStdStringW &text) const;
+ bool Update(const CStdString &text, float maxWidth = 0, bool forceUpdate = false, bool forceLTRReadingOrder = false);
+ void SetText(const CStdStringW &text, float maxWidth = 0, bool forceLTRReadingOrder = false);
+
+ unsigned int GetTextLength() const;
+ void GetFirstText(vecText &text) const;
+ void Reset();
+
+ void SetWrap(bool bWrap=true);
+ void SetMaxHeight(float fHeight);
+
+
+ static void DrawText(CGUIFont *font, float x, float y, color_t color, color_t shadowColor, const CStdString &text, uint32_t align);
+ static void DrawOutlineText(CGUIFont *font, float x, float y, color_t color, color_t outlineColor, uint32_t outlineWidth, const CStdString &text);
+ static void Filter(CStdString &text);
+
+protected:
+ void ParseText(const CStdStringW &text, vecText &parsedText);
+ void LineBreakText(const vecText &text, std::vector<CGUIString> &lines);
+ void WrapText(const vecText &text, float maxWidth);
+ void BidiTransform(std::vector<CGUIString> &lines, bool forceLTRReadingOrder);
+ CStdStringW BidiFlip(const CStdStringW &text, bool forceLTRReadingOrder);
+ void CalcTextExtent();
+
+ // our text to render
+ vecColors m_colors;
+ std::vector<CGUIString> m_lines;
+ typedef std::vector<CGUIString>::iterator iLine;
+
+ // the layout and font details
+ CGUIFont *m_font; // has style, colour info
+ bool m_wrap; // wrapping (true if justify is enabled!)
+ float m_maxHeight;
+ // the default color (may differ from the font objects defaults)
+ color_t m_textColor;
+
+ CStdString m_lastText;
+ float m_textWidth;
+ float m_textHeight;
+private:
+ inline bool IsSpace(character_t letter) const XBMC_FORCE_INLINE
+ {
+ return (letter & 0xffff) == L' ';
+ };
+ inline bool CanWrapAtLetter(character_t letter) const XBMC_FORCE_INLINE
+ {
+ character_t ch = letter & 0xffff;
+ return ch == L' ' || (ch >=0x4e00 && ch <= 0x9fff);
+ };
+ static void AppendToUTF32(const CStdString &utf8, character_t colStyle, vecText &utf32);
+ static void AppendToUTF32(const CStdStringW &utf16, character_t colStyle, vecText &utf32);
+ static void DrawOutlineText(CGUIFont *font, float x, float y, const vecColors &colors, color_t outlineColor, uint32_t outlineWidth, const vecText &text, uint32_t align, float maxWidth);
+ static void ParseText(const CStdStringW &text, uint32_t defaultStyle, vecColors &colors, vecText &parsedText);
+
+ static void utf8ToW(const CStdString &utf8, CStdStringW &utf16);
+};
+
diff --git a/guilib/GUITexture.cpp b/guilib/GUITexture.cpp
new file mode 100644
index 0000000000..adb8877f40
--- /dev/null
+++ b/guilib/GUITexture.cpp
@@ -0,0 +1,600 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUITexture.h"
+#include "GraphicContext.h"
+#include "TextureManager.h"
+#include "GUILargeTextureManager.h"
+#include "MathUtils.h"
+
+using namespace std;
+
+CGUITextureBase::CGUITextureBase(float posX, float posY, float width, float height, const CTextureInfo& texture)
+{
+ m_posX = posX;
+ m_posY = posY;
+ m_width = width;
+ m_height = height;
+ m_info = texture;
+
+ // defaults
+ m_visible = true;
+ m_diffuseColor = 0xffffffff;
+ m_alpha = 0xff;
+
+ m_vertex.SetRect(m_posX, m_posY, m_posX + m_width, m_posY + m_height);
+
+ m_frameWidth = 0;
+ m_frameHeight = 0;
+
+ m_texCoordsScaleU = 1.0f;
+ m_texCoordsScaleV = 1.0f;
+ m_diffuseU = 1.0f;
+ m_diffuseV = 1.0f;
+ m_diffuseScaleU = 1.0f;
+ m_diffuseScaleV = 1.0f;
+ m_largeOrientation = 0;
+
+ // anim gifs
+ m_currentFrame = 0;
+ m_frameCounter = (DWORD) -1;
+ m_currentLoop = 0;
+
+ m_allocateDynamically = false;
+ m_isAllocated = NO;
+ m_invalid = true;
+}
+
+CGUITextureBase::CGUITextureBase(const CGUITextureBase &right)
+{
+ m_posX = right.m_posX;
+ m_posY = right.m_posY;
+ m_width = right.m_width;
+ m_height = right.m_height;
+ m_info = right.m_info;
+
+ m_visible = right.m_visible;
+ m_diffuseColor = right.m_diffuseColor;
+ m_alpha = right.m_alpha;
+ m_aspect = right.m_aspect;
+
+ m_allocateDynamically = right.m_allocateDynamically;
+
+ // defaults
+ m_vertex.SetRect(m_posX, m_posY, m_posX + m_width, m_posY + m_height);
+
+ m_frameWidth = 0;
+ m_frameHeight = 0;
+
+ m_texCoordsScaleU = 1.0f;
+ m_texCoordsScaleV = 1.0f;
+ m_diffuseU = 1.0f;
+ m_diffuseV = 1.0f;
+ m_diffuseScaleU = 1.0f;
+ m_diffuseScaleV = 1.0f;
+
+ m_largeOrientation = 0;
+
+ m_currentFrame = 0;
+ m_frameCounter = (DWORD) -1;
+ m_currentLoop = 0;
+
+ m_isAllocated = NO;
+ m_invalid = true;
+}
+
+CGUITextureBase::~CGUITextureBase(void)
+{
+}
+
+void CGUITextureBase::AllocateOnDemand()
+{
+ if (m_visible)
+ { // visible, so make sure we're allocated
+ if (!IsAllocated() || (m_info.useLarge && !m_texture.size()))
+ AllocResources();
+ }
+ else
+ { // hidden, so deallocate as applicable
+ if (m_allocateDynamically && IsAllocated())
+ FreeResources();
+ // reset animated textures (animgifs)
+ m_currentLoop = 0;
+ m_currentFrame = 0;
+ m_frameCounter = 0;
+ }
+}
+
+void CGUITextureBase::Render()
+{
+ // check if we need to allocate our resources
+ AllocateOnDemand();
+
+ if (!m_visible || !m_texture.size())
+ return;
+
+ if (m_texture.size() > 1)
+ UpdateAnimFrame();
+
+ if (m_invalid)
+ CalculateSize();
+
+ // see if we need to clip the image
+ if (m_vertex.Width() > m_width || m_vertex.Height() > m_height)
+ {
+ if (!g_graphicsContext.SetClipRegion(m_posX, m_posY, m_width, m_height))
+ return;
+ }
+
+ // setup our renderer
+ Begin();
+
+ // compute the texture coordinates
+ float u1, u2, u3, v1, v2, v3;
+ u1 = m_info.border.left;
+ u2 = m_frameWidth - m_info.border.right;
+ u3 = m_frameWidth;
+ v1 = m_info.border.top;
+ v2 = m_frameHeight - m_info.border.bottom;
+ v3 = m_frameHeight;
+
+ if (!m_texture.m_texCoordsArePixels)
+ {
+ u1 *= m_texCoordsScaleU;
+ u2 *= m_texCoordsScaleU;
+ u3 *= m_texCoordsScaleU;
+ v1 *= m_texCoordsScaleV;
+ v2 *= m_texCoordsScaleV;
+ v3 *= m_texCoordsScaleV;
+ }
+
+ // TODO: The diffuse coloring applies to all vertices, which will
+ // look weird for stuff with borders, as will the -ve height/width
+ // for flipping
+
+ // left segment (0,0,u1,v3)
+ if (m_info.border.left)
+ {
+ if (m_info.border.top)
+ Render(m_vertex.x1, m_vertex.y1, m_vertex.x1 + m_info.border.left, m_vertex.y1 + m_info.border.top, 0, 0, u1, v1, u3, v3);
+ Render(m_vertex.x1, m_vertex.y1 + m_info.border.top, m_vertex.x1 + m_info.border.left, m_vertex.y2 - m_info.border.bottom, 0, v1, u1, v2, u3, v3);
+ if (m_info.border.bottom)
+ Render(m_vertex.x1, m_vertex.y2 - m_info.border.bottom, m_vertex.x1 + m_info.border.left, m_vertex.y2, 0, v2, u1, v3, u3, v3);
+ }
+ // middle segment (u1,0,u2,v3)
+ if (m_info.border.top)
+ Render(m_vertex.x1 + m_info.border.left, m_vertex.y1, m_vertex.x2 - m_info.border.right, m_vertex.y1 + m_info.border.top, u1, 0, u2, v1, u3, v3);
+ Render(m_vertex.x1 + m_info.border.left, m_vertex.y1 + m_info.border.top, m_vertex.x2 - m_info.border.right, m_vertex.y2 - m_info.border.bottom, u1, v1, u2, v2, u3, v3);
+ if (m_info.border.bottom)
+ Render(m_vertex.x1 + m_info.border.left, m_vertex.y2 - m_info.border.bottom, m_vertex.x2 - m_info.border.right, m_vertex.y2, u1, v2, u2, v3, u3, v3);
+ // right segment
+ if (m_info.border.right)
+ { // have a left border
+ if (m_info.border.top)
+ Render(m_vertex.x2 - m_info.border.right, m_vertex.y1, m_vertex.x2, m_vertex.y1 + m_info.border.top, u2, 0, u3, v1, u3, v3);
+ Render(m_vertex.x2 - m_info.border.right, m_vertex.y1 + m_info.border.top, m_vertex.x2, m_vertex.y2 - m_info.border.bottom, u2, v1, u3, v2, u3, v3);
+ if (m_info.border.bottom)
+ Render(m_vertex.x2 - m_info.border.right, m_vertex.y2 - m_info.border.bottom, m_vertex.x2, m_vertex.y2, u2, v2, u3, v3, u3, v3);
+ }
+
+ // close off our renderer
+ End();
+
+ if (m_vertex.Width() > m_width || m_vertex.Height() > m_height)
+ g_graphicsContext.RestoreClipRegion();
+}
+
+void CGUITextureBase::Render(float left, float top, float right, float bottom, float u1, float v1, float u2, float v2, float u3, float v3)
+{
+ CRect diffuse(u1, v1, u2, v2);
+ CRect texture(u1, v1, u2, v2);
+ CRect vertex(left, top, right, bottom);
+ g_graphicsContext.ClipRect(vertex, texture, m_diffuse.size() ? &diffuse : NULL);
+
+ if (vertex.IsEmpty())
+ return; // nothing to render
+
+ int orientation = GetOrientation();
+ OrientateTexture(texture, u3, v3, orientation);
+
+ if (m_diffuse.size())
+ {
+ // flip the texture as necessary. Diffuse just gets flipped according to m_info.orientation.
+ // Main texture gets flipped according to GetOrientation().
+ diffuse.x1 *= m_diffuseScaleU / u3; diffuse.x2 *= m_diffuseScaleU / u3;
+ diffuse.y1 *= m_diffuseScaleV / v3; diffuse.y2 *= m_diffuseScaleV / v3;
+ diffuse += m_diffuseOffset;
+ OrientateTexture(diffuse, m_diffuseU, m_diffuseV, m_info.orientation);
+ }
+
+ float x[4], y[4], z[4];
+
+#define ROUND_TO_PIXEL(x) (float)(MathUtils::round_int(x))
+
+ x[0] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalXCoord(vertex.x1, vertex.y1));
+ y[0] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalYCoord(vertex.x1, vertex.y1));
+ z[0] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalZCoord(vertex.x1, vertex.y1));
+ x[1] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalXCoord(vertex.x2, vertex.y1));
+ y[1] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalYCoord(vertex.x2, vertex.y1));
+ z[1] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalZCoord(vertex.x2, vertex.y1));
+ x[2] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalXCoord(vertex.x2, vertex.y2));
+ y[2] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalYCoord(vertex.x2, vertex.y2));
+ z[2] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalZCoord(vertex.x2, vertex.y2));
+ x[3] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalXCoord(vertex.x1, vertex.y2));
+ y[3] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalYCoord(vertex.x1, vertex.y2));
+ z[3] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalZCoord(vertex.x1, vertex.y2));
+
+ if (y[2] == y[0]) y[2] += 1.0f; if (x[2] == x[0]) x[2] += 1.0f;
+ if (y[3] == y[1]) y[3] += 1.0f; if (x[3] == x[1]) x[3] += 1.0f;
+
+#define MIX_ALPHA(a,c) (((a * (c >> 24)) / 255) << 24) | (c & 0x00ffffff)
+
+ color_t color = m_diffuseColor;
+ if (m_alpha != 0xFF) color = MIX_ALPHA(m_alpha, m_diffuseColor);
+ color = g_graphicsContext.MergeAlpha(color);
+
+ Draw(x, y, z, texture, diffuse, color, orientation);
+}
+
+void CGUITextureBase::AllocResources()
+{
+ if (m_info.filename.IsEmpty())
+ return;
+
+ if (m_texture.size())
+ return; // already have our texture
+
+ // reset our animstate
+ m_frameCounter = 0;
+ m_currentFrame = 0;
+ m_currentLoop = 0;
+
+ if (m_info.useLarge)
+ { // we want to use the large image loader, but we first check for bundled textures
+ if (!IsAllocated())
+ {
+ int images = g_TextureManager.Load(m_info.filename, true);
+ if (images)
+ {
+ m_isAllocated = NORMAL;
+ m_texture = g_TextureManager.GetTexture(m_info.filename);
+ }
+ }
+ if (m_isAllocated != NORMAL)
+ { // use our large image background loader
+ CTextureArray texture;
+ if (g_largeTextureManager.GetImage(m_info.filename, texture, m_largeOrientation, !IsAllocated()))
+ {
+ m_isAllocated = LARGE;
+
+ if (!texture.size()) // not ready as yet
+ return;
+
+ m_texture = texture;
+ }
+ else
+ m_isAllocated = LARGE_FAILED;
+ }
+ }
+ else if (!IsAllocated())
+ {
+ int images = g_TextureManager.Load(m_info.filename);
+
+ // set allocated to true even if we couldn't load the image to save
+ // us hitting the disk every frame
+ m_isAllocated = images ? NORMAL : NORMAL_FAILED;
+ if (!images)
+ return;
+
+ m_texture = g_TextureManager.GetTexture(m_info.filename);
+ }
+ m_frameWidth = (float)m_texture.m_width;
+ m_frameHeight = (float)m_texture.m_height;
+
+ // load the diffuse texture (if necessary)
+ if (!m_info.diffuse.IsEmpty())
+ {
+ g_TextureManager.Load(m_info.diffuse);
+ m_diffuse = g_TextureManager.GetTexture(m_info.diffuse);
+ }
+
+ CalculateSize();
+
+ // call our implementation
+ Allocate();
+}
+
+void CGUITextureBase::CalculateSize()
+{
+ if (m_currentFrame >= m_texture.size())
+ return;
+
+ m_texCoordsScaleU = 1.0f / m_texture.m_texWidth;
+ m_texCoordsScaleV = 1.0f / m_texture.m_texHeight;
+
+ if (m_width == 0)
+ m_width = m_frameWidth;
+ if (m_height == 0)
+ m_height = m_frameHeight;
+
+ float newPosX = m_posX;
+ float newPosY = m_posY;
+ float newWidth = m_width;
+ float newHeight = m_height;
+
+ if (m_aspect.ratio != CAspectRatio::AR_STRETCH && m_frameWidth && m_frameHeight)
+ {
+ // to get the pixel ratio, we must use the SCALED output sizes
+ float pixelRatio = g_graphicsContext.GetScalingPixelRatio();
+
+ float fSourceFrameRatio = m_frameWidth / m_frameHeight;
+ if (GetOrientation() & 4)
+ fSourceFrameRatio = m_frameHeight / m_frameWidth;
+ float fOutputFrameRatio = fSourceFrameRatio / pixelRatio;
+
+ // maximize the width
+ newHeight = m_width / fOutputFrameRatio;
+
+ if ((m_aspect.ratio == CAspectRatio::AR_SCALE && newHeight < m_height) ||
+ (m_aspect.ratio == CAspectRatio::AR_KEEP && newHeight > m_height))
+ {
+ newHeight = m_height;
+ newWidth = newHeight * fOutputFrameRatio;
+ }
+ if (m_aspect.ratio == CAspectRatio::AR_CENTER)
+ { // keep original size + center
+ newWidth = m_frameWidth;
+ newHeight = m_frameHeight;
+ }
+
+ if (m_aspect.align & ASPECT_ALIGN_LEFT)
+ newPosX = m_posX;
+ else if (m_aspect.align & ASPECT_ALIGN_RIGHT)
+ newPosX = m_posX + m_width - newWidth;
+ else
+ newPosX = m_posX + (m_width - newWidth) * 0.5f;
+ if (m_aspect.align & ASPECT_ALIGNY_TOP)
+ newPosY = m_posY;
+ else if (m_aspect.align & ASPECT_ALIGNY_BOTTOM)
+ newPosY = m_posY + m_height - newHeight;
+ else
+ newPosY = m_posY + (m_height - newHeight) * 0.5f;
+ }
+ m_vertex.SetRect(newPosX, newPosY, newPosX + newWidth, newPosY + newHeight);
+
+ // scale the diffuse coords as well
+ if (m_diffuse.size())
+ { // calculate scaling for the texcoords
+ if (m_diffuse.m_texCoordsArePixels)
+ {
+ m_diffuseU = float(m_diffuse.m_width);
+ m_diffuseV = float(m_diffuse.m_height);
+ }
+ else
+ {
+ m_diffuseU = float(m_diffuse.m_width) / float(m_diffuse.m_texWidth);
+ m_diffuseV = float(m_diffuse.m_height) / float(m_diffuse.m_texHeight);
+ }
+
+ if (m_aspect.scaleDiffuse)
+ {
+ m_diffuseScaleU = m_diffuseU;
+ m_diffuseScaleV = m_diffuseV;
+ m_diffuseOffset = CPoint(0,0);
+ }
+ else // stretch'ing diffuse
+ { // scale diffuse up or down to match output rect size, rather than image size
+ //(m_fX, mfY) -> (m_fX + m_fNW, m_fY + m_fNH)
+ //(0,0) -> (m_fU*m_diffuseScaleU, m_fV*m_diffuseScaleV)
+ // x = u/(m_fU*m_diffuseScaleU)*m_fNW + m_fX
+ // -> u = (m_posX - m_fX) * m_fU * m_diffuseScaleU / m_fNW
+ m_diffuseScaleU = m_diffuseU * m_vertex.Width() / m_width;
+ m_diffuseScaleV = m_diffuseV * m_vertex.Height() / m_height;
+ m_diffuseOffset = CPoint((m_vertex.x1 - m_posX) / m_vertex.Width() * m_diffuseScaleU, (m_vertex.y1 - m_posY) / m_vertex.Height() * m_diffuseScaleV);
+ }
+ }
+ m_invalid = false;
+}
+
+void CGUITextureBase::FreeResources(bool immediately /* = false */)
+{
+ if (m_isAllocated == LARGE || m_isAllocated == LARGE_FAILED)
+ g_largeTextureManager.ReleaseImage(m_info.filename, immediately);
+ else if (m_isAllocated == NORMAL && m_texture.size())
+ g_TextureManager.ReleaseTexture(m_info.filename);
+
+ if (m_diffuse.size())
+ g_TextureManager.ReleaseTexture(m_info.diffuse);
+ m_diffuse.Reset();
+
+ m_texture.Reset();
+
+ m_currentFrame = 0;
+ m_currentLoop = 0;
+ m_texCoordsScaleU = 1.0f;
+ m_texCoordsScaleV = 1.0f;
+ m_largeOrientation = 0;
+
+ // call our implementation
+ Free();
+
+ m_isAllocated = NO;
+}
+
+void CGUITextureBase::DynamicResourceAlloc(bool allocateDynamically)
+{
+ m_allocateDynamically = allocateDynamically;
+}
+
+void CGUITextureBase::UpdateAnimFrame()
+{
+ m_frameCounter++;
+ DWORD delay = m_texture.m_delays[m_currentFrame];
+ if (!delay) delay = 100;
+ if (m_frameCounter * 40 >= delay)
+ {
+ m_frameCounter = 0;
+ if (m_currentFrame + 1 >= m_texture.size())
+ {
+ if (m_texture.m_loops > 0)
+ {
+ if (m_currentLoop + 1 < m_texture.m_loops)
+ {
+ m_currentLoop++;
+ m_currentFrame = 0;
+ }
+ }
+ else
+ {
+ // 0 == loop forever
+ m_currentFrame = 0;
+ }
+ }
+ else
+ {
+ m_currentFrame++;
+ }
+ }
+}
+
+void CGUITextureBase::SetVisible(bool visible)
+{
+ m_visible = visible;
+}
+
+void CGUITextureBase::SetAlpha(unsigned char alpha)
+{
+ m_alpha = alpha;
+}
+
+void CGUITextureBase::SetDiffuseColor(color_t color)
+{
+ m_diffuseColor = color;
+}
+
+bool CGUITextureBase::ReadyToRender() const
+{
+ return m_texture.size() > 0;
+}
+
+void CGUITextureBase::OrientateTexture(CRect &rect, float width, float height, int orientation)
+{
+ switch (orientation & 3)
+ {
+ case 0:
+ // default
+ break;
+ case 1:
+ // flip in X direction
+ rect.x1 = width - rect.x1;
+ rect.x2 = width - rect.x2;
+ break;
+ case 2:
+ // rotate 180 degrees
+ rect.x1 = width - rect.x1;
+ rect.x2 = width - rect.x2;
+ rect.y1 = height - rect.y1;
+ rect.y2 = height - rect.y2;
+ break;
+ case 3:
+ // flip in Y direction
+ rect.y1 = height - rect.y1;
+ rect.y2 = height - rect.y2;
+ break;
+ }
+ if (orientation & 4)
+ {
+ // we need to swap x and y coordinates but only within the width,height block
+ float temp = rect.x1;
+ rect.x1 = rect.y1 * width/height;
+ rect.y1 = temp * height/width;
+ temp = rect.x2;
+ rect.x2 = rect.y2 * width/height;
+ rect.y2 = temp * height/width;
+ }
+}
+
+void CGUITextureBase::SetWidth(float width)
+{
+ if (width < m_info.border.left + m_info.border.right)
+ width = m_info.border.left + m_info.border.right;
+ if (m_width != width)
+ {
+ m_width = width;
+ m_invalid = true;
+ }
+}
+
+void CGUITextureBase::SetHeight(float height)
+{
+ if (height < m_info.border.top + m_info.border.bottom)
+ height = m_info.border.top + m_info.border.bottom;
+ if (m_height != height)
+ {
+ m_height = height;
+ m_invalid = true;
+ }
+}
+
+void CGUITextureBase::SetPosition(float posX, float posY)
+{
+ if (m_posX != posX || m_posY != posY)
+ {
+ m_posX = posX;
+ m_posY = posY;
+ m_invalid = true;
+ }
+}
+
+void CGUITextureBase::SetAspectRatio(const CAspectRatio &aspect)
+{
+ if (m_aspect != aspect)
+ {
+ m_aspect = aspect;
+ m_invalid = true;
+ }
+}
+
+void CGUITextureBase::SetFileName(const CStdString& filename)
+{
+ if (m_info.filename.Equals(filename)) return;
+ // Don't completely free resources here - we may be just changing
+ // filenames mid-animation
+ FreeResources();
+ m_info.filename = filename;
+ // Don't allocate resources here as this is done at render time
+}
+
+int CGUITextureBase::GetOrientation() const
+{
+ if (m_isAllocated == LARGE)
+ return m_info.orientation;
+ // otherwise multiply our orientations
+ static char orient_table[] = { 0, 1, 2, 3, 4, 5, 6, 7,
+ 1, 0, 3, 2, 5, 4, 7, 6,
+ 2, 3, 0, 1, 6, 7, 4, 5,
+ 3, 2, 1, 0, 7, 6, 5, 4,
+ 4, 7, 6, 5, 0, 3, 2, 1,
+ 5, 6, 7, 4, 1, 2, 3, 0,
+ 6, 5, 4, 7, 2, 1, 0, 3,
+ 7, 4, 5, 6, 3, 0, 1, 2 };
+ return (int)orient_table[8 * m_info.orientation + m_largeOrientation];
+}
diff --git a/guilib/GUITexture.h b/guilib/GUITexture.h
new file mode 100644
index 0000000000..91816a52a5
--- /dev/null
+++ b/guilib/GUITexture.h
@@ -0,0 +1,215 @@
+/*!
+\file GUITexture.h
+\brief
+*/
+
+#ifndef GUILIB_GUITEXTURE_H
+#define GUILIB_GUITEXTURE_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "TextureManager.h"
+#include "Geometry.h"
+
+typedef uint32_t color_t;
+
+struct FRECT
+{
+ float left;
+ float top;
+ float right;
+ float bottom;
+};
+
+// image alignment for <aspect>keep</aspect>, <aspect>scale</aspect> or <aspect>center</aspect>
+#define ASPECT_ALIGN_CENTER 0
+#define ASPECT_ALIGN_LEFT 1
+#define ASPECT_ALIGN_RIGHT 2
+#define ASPECT_ALIGNY_CENTER 0
+#define ASPECT_ALIGNY_TOP 4
+#define ASPECT_ALIGNY_BOTTOM 8
+#define ASPECT_ALIGN_MASK 3
+#define ASPECT_ALIGNY_MASK ~3
+
+class CAspectRatio
+{
+public:
+ enum ASPECT_RATIO { AR_STRETCH = 0, AR_SCALE, AR_KEEP, AR_CENTER };
+ CAspectRatio(ASPECT_RATIO aspect = AR_STRETCH)
+ {
+ ratio = aspect;
+ align = ASPECT_ALIGN_CENTER | ASPECT_ALIGNY_CENTER;
+ scaleDiffuse = true;
+ };
+ bool operator!=(const CAspectRatio &right) const
+ {
+ if (ratio != right.ratio) return true;
+ if (align != right.align) return true;
+ if (scaleDiffuse != right.scaleDiffuse) return true;
+ return false;
+ };
+
+ ASPECT_RATIO ratio;
+ uint32_t align;
+ bool scaleDiffuse;
+};
+
+class CTextureInfo
+{
+public:
+ CTextureInfo()
+ {
+ memset(&border, 0, sizeof(FRECT));
+ orientation = 0;
+ useLarge = false;
+ };
+
+ CTextureInfo(const CStdString &file)
+ {
+ memset(&border, 0, sizeof(FRECT));
+ orientation = 0;
+ useLarge = false;
+ filename = file;
+ }
+
+ void operator=(const CTextureInfo &right)
+ {
+ memcpy(&border, &right.border, sizeof(FRECT));
+ orientation = right.orientation;
+ diffuse = right.diffuse;
+ filename = right.filename;
+ useLarge = right.useLarge;
+ };
+ bool useLarge;
+ FRECT border; // scaled - unneeded if we get rid of scale on load
+ int orientation; // orientation of the texture (0 - 7 == EXIForientation - 1)
+ CStdString diffuse; // diffuse overlay texture
+ CStdString filename; // main texture file
+};
+
+class CGUITextureBase
+{
+public:
+ CGUITextureBase(float posX, float posY, float width, float height, const CTextureInfo& texture);
+ CGUITextureBase(const CGUITextureBase &left);
+ virtual ~CGUITextureBase(void);
+
+ void Render();
+
+ void DynamicResourceAlloc(bool bOnOff);
+ void AllocResources();
+ void FreeResources(bool immediately = false);
+
+ void SetVisible(bool visible);
+ void SetAlpha(unsigned char alpha);
+ void SetDiffuseColor(color_t color);
+ void SetPosition(float x, float y);
+ void SetWidth(float width);
+ void SetHeight(float height);
+ void SetFileName(const CStdString &filename);
+ void SetAspectRatio(const CAspectRatio &aspect);
+
+ const CStdString& GetFileName() const { return m_info.filename; };
+ float GetTextureWidth() const { return m_frameWidth; };
+ float GetTextureHeight() const { return m_frameHeight; };
+ float GetWidth() const { return m_width; };
+ float GetHeight() const { return m_height; };
+ float GetXPosition() const { return m_posX; };
+ float GetYPosition() const { return m_posY; };
+ int GetOrientation() const;
+ const CRect &GetRenderRect() const { return m_vertex; };
+ bool IsLazyLoaded() const { return m_info.useLarge; };
+
+ bool HitTest(const CPoint &point) const { return CRect(m_posX, m_posY, m_posX + m_width, m_posY + m_height).PtInRect(point); };
+ bool IsAllocated() const { return m_isAllocated != NO; };
+ bool FailedToAlloc() const { return m_isAllocated == NORMAL_FAILED || m_isAllocated == LARGE_FAILED; };
+ bool ReadyToRender() const;
+protected:
+ void CalculateSize();
+ void LoadDiffuseImage();
+ void AllocateOnDemand();
+ void UpdateAnimFrame();
+ void Render(float left, float top, float bottom, float right, float u1, float v1, float u2, float v2, float u3, float v3);
+ void OrientateTexture(CRect &rect, float width, float height, int orientation);
+
+ // functions that our implementation classes handle
+ virtual void Allocate() {}; ///< called after our textures have been allocated
+ virtual void Free() {}; ///< called after our textures have been freed
+ virtual void Begin() {};
+ virtual void Draw(float *x, float *y, float *z, const CRect &texture, const CRect &diffuse, color_t color, int orientation)=0;
+ virtual void End() {};
+
+ bool m_visible;
+ color_t m_diffuseColor;
+
+ float m_posX; // size of the frame
+ float m_posY;
+ float m_width;
+ float m_height;
+
+ CRect m_vertex; // vertex coords to render
+ bool m_invalid; // if true, we need to recalculate
+
+ unsigned char m_alpha;
+
+ float m_frameWidth, m_frameHeight; // size in pixels of the actual frame within the texture
+ float m_texCoordsScaleU, m_texCoordsScaleV; // scale factor for pixel->texture coordinates
+
+ // animations
+ int m_currentLoop;
+ unsigned int m_currentFrame;
+ DWORD m_frameCounter;
+
+ float m_diffuseU, m_diffuseV; // size of the diffuse frame (in tex coords)
+ float m_diffuseScaleU, m_diffuseScaleV; // scale factor of the diffuse frame (from texture coords to diffuse tex coords)
+ CPoint m_diffuseOffset; // offset into the diffuse frame (it's not always the origin)
+
+ bool m_allocateDynamically;
+ enum ALLOCATE_TYPE { NO = 0, NORMAL, LARGE, NORMAL_FAILED, LARGE_FAILED };
+ ALLOCATE_TYPE m_isAllocated;
+
+ CTextureInfo m_info;
+ CAspectRatio m_aspect;
+
+ int m_largeOrientation; // orientation for large textures
+
+ CTextureArray m_diffuse;
+ CTextureArray m_texture;
+};
+
+
+#if defined(HAS_SDL_2D)
+#include "GUITextureSDL.h"
+#elif defined(HAS_GL)
+#include "GUITextureGL.h"
+#define CGUITexture CGUITextureGL
+#elif defined(HAS_GLES)
+#include "GUITextureGLES.h"
+#define CGUITexture CGUITextureGLES
+#elif defined(HAS_DX)
+#include "GUITextureD3D.h"
+#define CGUITexture CGUITextureD3D
+#endif
+
+#endif
diff --git a/guilib/GUITextureD3D.cpp b/guilib/GUITextureD3D.cpp
new file mode 100644
index 0000000000..27f341a284
--- /dev/null
+++ b/guilib/GUITextureD3D.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "Texture.h"
+#include "GUITextureD3D.h"
+#include "WindowingFactory.h"
+
+#ifdef HAS_DX
+
+CGUITextureD3D::CGUITextureD3D(float posX, float posY, float width, float height, const CTextureInfo &texture)
+: CGUITextureBase(posX, posY, width, height, texture)
+{
+}
+
+void CGUITextureD3D::Begin()
+{
+ CBaseTexture* texture = m_texture.m_textures[m_currentFrame];
+ LPDIRECT3DDEVICE9 p3DDevice = g_Windowing.Get3DDevice();
+
+ texture->LoadToGPU();
+ if (m_diffuse.size())
+ m_diffuse.m_textures[0]->LoadToGPU();
+ // Set state to render the image
+ p3DDevice->SetTexture( 0, texture->GetTextureObject() );
+ p3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+ p3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+ p3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
+ p3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
+ p3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
+ p3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
+ p3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
+ p3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
+ p3DDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
+ p3DDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
+ if (m_diffuse.size())
+ {
+ p3DDevice->SetTexture( 1, m_diffuse.m_textures[0]->GetTextureObject() );
+ p3DDevice->SetSamplerState( 1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
+ p3DDevice->SetSamplerState( 1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
+ p3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
+ p3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT );
+ p3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE );
+ p3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
+ p3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT );
+ p3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
+ p3DDevice->SetSamplerState( 1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
+ p3DDevice->SetSamplerState( 1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
+ }
+
+ p3DDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
+ p3DDevice->SetRenderState( D3DRS_ALPHAREF, 0 );
+ p3DDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
+ p3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
+ p3DDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );
+ p3DDevice->SetRenderState( D3DRS_FOGTABLEMODE, D3DFOG_NONE );
+ p3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
+ p3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
+ p3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
+ p3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
+ p3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
+ p3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE);
+
+ p3DDevice->SetFVF( D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX2 );
+}
+
+void CGUITextureD3D::End()
+{
+ // unset the texture and palette or the texture caching crashes because the runtime still has a reference
+ g_Windowing.Get3DDevice()->SetTexture( 0, NULL );
+ if (m_diffuse.size())
+ g_Windowing.Get3DDevice()->SetTexture( 1, NULL );
+}
+
+void CGUITextureD3D::Draw(float *x, float *y, float *z, const CRect &texture, const CRect &diffuse, color_t color, int orientation)
+{
+ struct CUSTOMVERTEX {
+ FLOAT x, y, z;
+ DWORD color;
+ FLOAT tu, tv; // Texture coordinates
+ FLOAT tu2, tv2;
+ };
+
+ // D3D aligns to half pixel boundaries
+ for (int i = 0; i < 4; i++)
+ {
+ x[i] -= 0.5f;
+ y[i] -= 0.5f;
+ z[i] -= 0.5f;
+ };
+
+ CUSTOMVERTEX verts[4];
+ verts[0].x = x[0]; verts[0].y = y[0]; verts[0].z = z[0];
+ verts[0].tu = texture.x1; verts[0].tv = texture.y1;
+ verts[0].tu2 = diffuse.x1; verts[0].tv2 = diffuse.y1;
+ verts[0].color = color;
+
+ verts[1].x = x[1]; verts[1].y = y[1]; verts[1].z = z[1];
+ if (orientation & 4)
+ {
+ verts[1].tu = texture.x1;
+ verts[1].tv = texture.y2;
+ }
+ else
+ {
+ verts[1].tu = texture.x2;
+ verts[1].tv = texture.y1;
+ }
+ if (m_info.orientation & 4)
+ {
+ verts[1].tu2 = diffuse.x1;
+ verts[1].tv2 = diffuse.y2;
+ }
+ else
+ {
+ verts[1].tu2 = diffuse.x2;
+ verts[1].tv2 = diffuse.y1;
+ }
+ verts[1].color = color;
+
+ verts[2].x = x[2]; verts[2].y = y[2]; verts[2].z = z[2];
+ verts[2].tu = texture.x2; verts[2].tv = texture.y2;
+ verts[2].tu2 = diffuse.x2; verts[2].tv2 = diffuse.y2;
+ verts[2].color = color;
+
+ verts[3].x = x[3]; verts[3].y = y[3]; verts[3].z = z[3];
+ if (orientation & 4)
+ {
+ verts[3].tu = texture.x2;
+ verts[3].tv = texture.y1;
+ }
+ else
+ {
+ verts[3].tu = texture.x1;
+ verts[3].tv = texture.y2;
+ }
+ if (m_info.orientation & 4)
+ {
+ verts[3].tu2 = diffuse.x2;
+ verts[3].tv2 = diffuse.y1;
+ }
+ else
+ {
+ verts[3].tu2 = diffuse.x1;
+ verts[3].tv2 = diffuse.y2;
+ }
+ verts[3].color = color;
+
+ g_Windowing.Get3DDevice()->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(CUSTOMVERTEX));
+}
+
+void CGUITextureD3D::DrawQuad(const CRect &rect, color_t color, CBaseTexture *texture, const CRect *texCoords)
+{
+ struct CUSTOMVERTEX {
+ FLOAT x, y, z;
+ DWORD color;
+ FLOAT tu, tv; // Texture coordinates
+ FLOAT tu2, tv2;
+ };
+
+ LPDIRECT3DDEVICE9 p3DDevice = g_Windowing.Get3DDevice();
+
+ if (texture)
+ {
+ texture->LoadToGPU();
+ // Set state to render the image
+ p3DDevice->SetTexture( 0, texture->GetTextureObject() );
+ p3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+ p3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+ p3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
+ p3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
+ p3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
+ p3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
+ p3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
+ p3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
+ p3DDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
+ p3DDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
+ }
+
+ p3DDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
+ p3DDevice->SetRenderState( D3DRS_ALPHAREF, 0 );
+ p3DDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
+ p3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
+ p3DDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );
+ p3DDevice->SetRenderState( D3DRS_FOGTABLEMODE, D3DFOG_NONE );
+ p3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
+ p3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
+ p3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
+ p3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
+ p3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
+ p3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE);
+
+ p3DDevice->SetFVF( D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX2 );
+
+ CRect coords = texCoords ? *texCoords : CRect(0.0f, 0.0f, 1.0f, 1.0f);
+ CUSTOMVERTEX verts[4] = {
+ { rect.x1 - 0.5f, rect.y1 - 0.5f, 0, color, coords.x1, coords.y1, 0, 0 },
+ { rect.x2 - 0.5f, rect.y1 - 0.5f, 0, color, coords.x2, coords.y1, 0, 0 },
+ { rect.x2 - 0.5f, rect.y2 - 0.5f, 0, color, coords.x2, coords.y2, 0, 0 },
+ { rect.x1 - 0.5f, rect.y2 - 0.5f, 0, color, coords.x1, coords.y2, 0, 0 },
+ };
+ p3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(CUSTOMVERTEX));
+
+ p3DDevice->SetTexture( 0, NULL );
+}
+
+#endif \ No newline at end of file
diff --git a/guilib/GUITextureD3D.h b/guilib/GUITextureD3D.h
new file mode 100644
index 0000000000..b168f685eb
--- /dev/null
+++ b/guilib/GUITextureD3D.h
@@ -0,0 +1,49 @@
+/*!
+\file GUITextureD3D.h
+\brief
+*/
+
+#ifndef GUILIB_GUITEXTURED3D_H
+#define GUILIB_GUITEXTURED3D_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUITexture.h"
+
+#ifdef HAS_DX
+
+class CGUITextureD3D : public CGUITextureBase
+{
+public:
+ CGUITextureD3D(float posX, float posY, float width, float height, const CTextureInfo& texture);
+ static void DrawQuad(const CRect &coords, color_t color, CBaseTexture *texture = NULL, const CRect *texCoords = NULL);
+protected:
+ void Begin();
+ void Draw(float *x, float *y, float *z, const CRect &texture, const CRect &diffuse, color_t color, int orientation);
+ void End();
+};
+
+#endif
+
+#endif \ No newline at end of file
diff --git a/guilib/GUITextureGL.cpp b/guilib/GUITextureGL.cpp
new file mode 100644
index 0000000000..8af30ff291
--- /dev/null
+++ b/guilib/GUITextureGL.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "GUITextureGL.h"
+#include "Texture.h"
+#include "utils/log.h"
+
+#if defined(HAS_GL)
+
+CGUITextureGL::CGUITextureGL(float posX, float posY, float width, float height, const CTextureInfo &texture)
+: CGUITextureBase(posX, posY, width, height, texture)
+{
+}
+
+void CGUITextureGL::Begin()
+{
+ CBaseTexture* texture = m_texture.m_textures[m_currentFrame];
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ texture->LoadToGPU();
+ if (m_diffuse.size())
+ m_diffuse.m_textures[0]->LoadToGPU();
+
+ glBindTexture(GL_TEXTURE_2D, texture->GetTextureObject());
+ glEnable(GL_TEXTURE_2D);
+
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND); // Turn Blending On
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+ // diffuse coloring
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);
+ glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
+ glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ VerifyGLState();
+
+ if (m_diffuse.size())
+ {
+ glActiveTextureARB(GL_TEXTURE1_ARB);
+ glBindTexture(GL_TEXTURE_2D, m_diffuse.m_textures[0]->GetTextureObject());
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE1);
+ glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
+ glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ VerifyGLState();
+ }
+ //glDisable(GL_TEXTURE_2D); // uncomment these 2 lines to switch to wireframe rendering
+ //glBegin(GL_LINE_LOOP);
+ glBegin(GL_QUADS);
+}
+
+void CGUITextureGL::End()
+{
+ glEnd();
+ if (m_diffuse.size())
+ {
+ glDisable(GL_TEXTURE_2D);
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ glDisable(GL_TEXTURE_2D);
+}
+
+void CGUITextureGL::Draw(float *x, float *y, float *z, const CRect &texture, const CRect &diffuse, color_t color, int orientation)
+{
+ GLubyte a = (GLubyte)GET_A(color);
+ GLubyte r = (GLubyte)GET_R(color);
+ GLubyte g = (GLubyte)GET_G(color);
+ GLubyte b = (GLubyte)GET_B(color);
+
+ // Top-left vertex (corner)
+ glColor4ub(r, g, b, a);
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texture.x1, texture.y1);
+ if (m_diffuse.size())
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, diffuse.x1, diffuse.y1);
+ glVertex3f(x[0], y[0], z[0]);
+
+ // Top-right vertex (corner)
+ glColor4ub(r, g, b, a);
+ if (orientation & 4)
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texture.x1, texture.y2);
+ else
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texture.x2, texture.y1);
+ if (m_diffuse.size())
+ {
+ if (m_info.orientation & 4)
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, diffuse.x1, diffuse.y2);
+ else
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, diffuse.x2, diffuse.y1);
+ }
+ glVertex3f(x[1], y[1], z[1]);
+
+ // Bottom-right vertex (corner)
+ glColor4ub(r, g, b, a);
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texture.x2, texture.y2);
+ if (m_diffuse.size())
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, diffuse.x2, diffuse.y2);
+ glVertex3f(x[2], y[2], z[2]);
+
+ // Bottom-left vertex (corner)
+ glColor4ub(r, g, b, a);
+ if (orientation & 4)
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texture.x2, texture.y1);
+ else
+ glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texture.x1, texture.y2);
+ if (m_diffuse.size())
+ {
+ if (m_info.orientation & 4)
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, diffuse.x2, diffuse.y1);
+ else
+ glMultiTexCoord2fARB(GL_TEXTURE1_ARB, diffuse.x1, diffuse.y2);
+ }
+ glVertex3f(x[3], y[3], z[3]);
+}
+
+void CGUITextureGL::DrawQuad(const CRect &rect, color_t color, CBaseTexture *texture, const CRect *texCoords)
+{
+ if (texture)
+ {
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ texture->LoadToGPU();
+ glBindTexture(GL_TEXTURE_2D, texture->GetTextureObject());
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE1);
+ glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
+ glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ }
+ else
+ glDisable(GL_TEXTURE_2D);
+
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND); // Turn Blending On
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+ // diffuse coloring
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);
+ glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
+ glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ VerifyGLState();
+
+ glBegin(GL_QUADS);
+
+ glColor4ub((GLubyte)GET_R(color), (GLubyte)GET_G(color), (GLubyte)GET_B(color), (GLubyte)GET_A(color));
+
+ CRect coords = texCoords ? *texCoords : CRect(0.0f, 0.0f, 1.0f, 1.0f);
+ glTexCoord2f(coords.x1, coords.y1);
+ glVertex3f(rect.x1, rect.y1, 0);
+ glTexCoord2f(coords.x2, coords.y1);
+ glVertex3f(rect.x2, rect.y1, 0);
+ glTexCoord2f(coords.x2, coords.y2);
+ glVertex3f(rect.x2, rect.y2, 0);
+ glTexCoord2f(coords.x1, coords.y2);
+ glVertex3f(rect.x1, rect.y2, 0);
+
+ glEnd();
+ if (texture)
+ glDisable(GL_TEXTURE_2D);
+}
+
+#endif
diff --git a/guilib/GUITextureGL.h b/guilib/GUITextureGL.h
new file mode 100644
index 0000000000..bf349f05dd
--- /dev/null
+++ b/guilib/GUITextureGL.h
@@ -0,0 +1,45 @@
+/*!
+\file GUITextureGL.h
+\brief
+*/
+
+#ifndef GUILIB_GUITEXTUREGL_H
+#define GUILIB_GUITEXTUREGL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUITexture.h"
+
+class CGUITextureGL : public CGUITextureBase
+{
+public:
+ CGUITextureGL(float posX, float posY, float width, float height, const CTextureInfo& texture);
+ static void DrawQuad(const CRect &coords, color_t color, CBaseTexture *texture = NULL, const CRect *texCoords = NULL);
+protected:
+ void Begin();
+ void Draw(float *x, float *y, float *z, const CRect &texture, const CRect &diffuse, color_t color, int orientation);
+ void End();
+};
+
+#endif
diff --git a/guilib/GUITextureGLES.cpp b/guilib/GUITextureGLES.cpp
new file mode 100644
index 0000000000..7f1458e22d
--- /dev/null
+++ b/guilib/GUITextureGLES.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "GUITextureGLES.h"
+#include "Texture.h"
+
+#if defined(HAS_GLES)
+
+CGUITextureGLES::CGUITextureGLES(float posX, float posY, float width, float height, const CTextureInfo &texture)
+: CGUITextureBase(posX, posY, width, height, texture)
+{
+ // TODO: OpenGLES
+}
+
+void CGUITextureGLES::Begin()
+{
+ // TODO: OpenGLES
+}
+
+void CGUITextureGLES::End()
+{
+ // TODO: OpenGLES
+}
+
+void CGUITextureGLES::Draw(float *x, float *y, float *z, const CRect &texture, const CRect &diffuse, DWORD color, int orientation)
+{
+ // TODO: OpenGLES
+}
+
+void CGUITextureGLES::DrawQuad(const CRect &rect, DWORD color)
+{
+ // TODO: OpenGLES
+}
+
+#endif
diff --git a/guilib/GUITextureGLES.h b/guilib/GUITextureGLES.h
new file mode 100644
index 0000000000..cbfce6ee4c
--- /dev/null
+++ b/guilib/GUITextureGLES.h
@@ -0,0 +1,45 @@
+/*!
+\file GUITextureGLES.h
+\brief
+*/
+
+#ifndef GUILIB_GUITEXTUREGLES_H
+#define GUILIB_GUITEXTUREGLES_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUITexture.h"
+
+class CGUITextureGLES : public CGUITextureBase
+{
+public:
+ CGUITextureGLES(float posX, float posY, float width, float height, const CTextureInfo& texture);
+ static void DrawQuad(const CRect &rect, DWORD color);
+protected:
+ void Begin();
+ void Draw(float *x, float *y, float *z, const CRect &texture, const CRect &diffuse, DWORD color, int orientation);
+ void End();
+};
+
+#endif
diff --git a/guilib/GUITextureSDL.cpp b/guilib/GUITextureSDL.cpp
new file mode 100644
index 0000000000..cacd66d865
--- /dev/null
+++ b/guilib/GUITextureSDL.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "GUITextureSDL.h"
+#include "GraphicContext.h"
+
+using namespace std;
+
+#ifdef HAS_SDL_2D
+
+CGUITextureSDL::CGUITextureSDL(float posX, float posY, float width, float height, const CTextureInfo &texture)
+: CGUITextureBase(posX, posY, width, height, texture)
+{
+}
+
+void CGUITextureSDL::Allocate()
+{
+ // allocate our cached textures
+ for (unsigned int i = 0; i < m_texture.size(); i++)
+ m_cachedTextures.push_back(CCachedTexture());
+}
+
+void CGUITextureSDL::Free()
+{
+ // free our cached textures
+ for( unsigned int i=0;i<m_cachedTextures.size();++i )
+ {
+ if (m_cachedTextures[i].surface)
+ SDL_FreeSurface(m_cachedTextures[i].surface);
+ }
+ m_cachedTextures.clear();
+}
+
+void CGUITextureSDL::Draw(float *x, float *y, float *z, const CRect &texture, const CRect &diffuse, color_t color, int orientation)
+{
+ SDL_Surface* surface = m_texture.m_textures[m_currentFrame];
+ float u[2] = { texture.x1, texture.x2 };
+ float v[2] = { texture.y1, texture.y2 };
+
+ // cache texture based on:
+ // 1. Bounding box
+ // 2. Diffuse color
+ int b[4];
+ CalcBoundingBox(x, y, 4, b);
+ CCachedTexture &cached = m_cachedTextures[m_currentFrame];
+ if (!cached.surface || cached.width != b[2] || cached.height != b[3] || color != cached.diffuseColor)
+ { // need to re-render the surface
+ RenderWithEffects(surface, x, y, u, v, &color, m_diffuse.size() ? m_diffuse.m_textures[0] : NULL, m_diffuseScaleU, m_diffuseScaleV, cached);
+ }
+ if (cached.surface)
+ {
+ SDL_Rect dst = { (Sint16)b[0], (Sint16)b[1], 0, 0 };
+ g_graphicsContext.BlitToScreen(cached.surface, NULL, &dst);
+ }
+}
+
+void CGUITextureSDL::CalcBoundingBox(float *x, float *y, int n, int *b)
+{
+ b[0] = (int)x[0], b[2] = 1;
+ b[1] = (int)y[0], b[3] = 1;
+ for (int i = 1; i < 4; ++i)
+ {
+ if (x[i] < b[0]) b[0] = (int)x[i];
+ if (y[i] < b[1]) b[1] = (int)y[i];
+ if (x[i]+1 > b[0] + b[2]) b[2] = (int)x[i]+1 - b[0];
+ if (y[i]+1 > b[1] + b[3]) b[3] = (int)y[i]+1 - b[1];
+ }
+}
+
+#define CLAMP(a,b,c) (a < b) ? b : ((a > c) ? c : a)
+
+void CGUITextureSDL::GetTexel(float tu, float tv, SDL_Surface *src, BYTE *texel)
+{
+ int pu1 = (int)floor(tu);
+ int pv1 = (int)floor(tv);
+ int pu2 = pu1+1, pv2 = pv1+1;
+ float du = tu - pu1;
+ float dv = tv - pv1;
+ pu1 = CLAMP(pu1,0,src->w-1);
+ pu2 = CLAMP(pu2,0,src->w-1);
+ pv1 = CLAMP(pv1,0,src->h-1);
+ pv2 = CLAMP(pv2,0,src->h-1);
+ BYTE *tex1 = (BYTE *)src->pixels + pv1 * src->pitch + pu1 * 4;
+ BYTE *tex2 = (BYTE *)src->pixels + pv1 * src->pitch + pu2 * 4;
+ BYTE *tex3 = (BYTE *)src->pixels + pv2 * src->pitch + pu1 * 4;
+ BYTE *tex4 = (BYTE *)src->pixels + pv2 * src->pitch + pu2 * 4;
+ // average these bytes
+ texel[0] = (BYTE)((*tex1++ * (1-du) + *tex2++ * du)*(1-dv) + (*tex3++ * (1-du) + *tex4++ * du) * dv);
+ texel[1] = (BYTE)((*tex1++ * (1-du) + *tex2++ * du)*(1-dv) + (*tex3++ * (1-du) + *tex4++ * du) * dv);
+ texel[2] = (BYTE)((*tex1++ * (1-du) + *tex2++ * du)*(1-dv) + (*tex3++ * (1-du) + *tex4++ * du) * dv);
+ texel[3] = (BYTE)((*tex1++ * (1-du) + *tex2++ * du)*(1-dv) + (*tex3++ * (1-du) + *tex4++ * du) * dv);
+}
+
+#define MODULATE(a,b) (b ? ((int)a*(b+1)) >> 8 : 0)
+#define ALPHA_BLEND(a,b,c) (c ? ((int)a*(c+1) + b*(255-c)) >> 8 : b)
+
+void CGUITextureSDL::RenderWithEffects(SDL_Surface *src, float *x, float *y, float *u, float *v, color_t *c, SDL_Surface *diffuse, float diffuseScaleU, float diffuseScaleV, CCachedTexture &dst)
+{
+ // renders the surface from u[0],v[0] -> u[1],v[1] into the parallelogram defined by x[0],y[0]...x[3],y[3]
+ // we create a new surface of the appropriate size, and render into it the resized and rotated texture,
+ // with diffuse modulation etc. as necessary.
+
+ // first create our surface
+ if (dst.surface)
+ SDL_FreeSurface(dst.surface);
+ // calculate the bounding box
+ int b[4];
+ CalcBoundingBox(x, y, 4, b);
+ dst.width = b[2]; dst.height = b[3];
+ dst.diffuseColor = c[0];
+
+ // create a new texture this size
+ dst.surface = SDL_CreateRGBSurface(SDL_HWSURFACE, dst.width+1, dst.height+1, 32, RMASK, GMASK, BMASK, AMASK);
+ if (!dst.surface)
+ return; // can't create surface
+
+ // vectors of parallelogram in screenspace
+ float ax = x[1] - x[0];
+ float ay = y[1] - y[0];
+ float bx = x[3] - x[0];
+ float by = y[3] - y[0];
+
+ // as we're mapping to a parallelogram, don't assume that the vectors are orthogonal (allows for skewed textures later, and no more computation)
+ // we want the coordinate vector wrt the basis vectors [ax,ay] and [bx,by], so invert the matrix [ax bx;ay by]
+ u[0] *= src->w;
+ v[0] *= src->h;
+ u[1] *= src->w;
+ v[1] *= src->h;
+
+ float det_m = ax * by - ay * bx;
+ float m[2][2];
+ m[0][0] = by / det_m * (u[1] - u[0]);
+ m[0][1] = -bx / det_m * (u[1] - u[0]);
+ m[1][0] = -ay / det_m * (v[1] - v[0]);
+ m[1][1] = ax / det_m * (v[1] - v[0]);
+
+ // we render from these values in our texture. Note that u[0] may be bigger than u[1] when flipping
+ const float minU = min(u[0], u[1]) - 0.5f;
+ const float maxU = max(u[0], u[1]) + 0.5f;
+ const float minV = min(v[0], v[1]) - 0.5f;
+ const float maxV = max(v[0], v[1]) + 0.5f;
+
+ SDL_LockSurface(dst.surface);
+ SDL_LockSurface(src);
+ if (diffuse)
+ {
+ SDL_LockSurface(diffuse);
+ diffuseScaleU *= diffuse->w / src->w;
+ diffuseScaleV *= diffuse->h / src->h;
+ }
+
+ // for speed, find the bounding box of our x, y
+ // for every pixel in the bounding box, find the corresponding texel
+ for (int sy = 0; sy <= dst.height; ++sy)
+ {
+ for (int sx = 0; sx <= dst.width; ++sx)
+ {
+ // find where this pixel corresponds in our texture
+ float tu = m[0][0] * (sx + b[0] - x[0] - 0.5f) + m[0][1] * (sy + b[1] - y[0] - 0.5f) + u[0];
+ float tv = m[1][0] * (sx + b[0] - x[0] - 0.5f) + m[1][1] * (sy + b[1] - y[0] - 0.5f) + v[0];
+ if (tu > minU && tu < maxU && tv > minV && tv < maxV)
+ { // in the texture - render it to screen
+ BYTE tex[4];
+ GetTexel(tu, tv, src, tex);
+ if (diffuse)
+ {
+ BYTE diff[4];
+ GetTexel(tu * diffuseScaleU, tv * diffuseScaleV, diffuse, diff);
+ tex[0] = MODULATE(tex[0], diff[0]);
+ tex[1] = MODULATE(tex[1], diff[1]);
+ tex[2] = MODULATE(tex[2], diff[2]);
+ tex[3] = MODULATE(tex[3], diff[3]);
+ }
+ // currently we just use a single color
+ BYTE *diffuse = (BYTE *)c;
+ BYTE *screen = (BYTE *)dst.surface->pixels + sy * dst.surface->pitch + sx*4;
+ screen[0] = MODULATE(tex[0], diffuse[0]);
+ screen[1] = MODULATE(tex[1], diffuse[1]);
+ screen[2] = MODULATE(tex[2], diffuse[2]);
+ screen[3] = MODULATE(tex[3], diffuse[3]);
+ }
+ }
+ }
+ SDL_UnlockSurface(src);
+ SDL_UnlockSurface(dst.surface);
+ if (diffuse)
+ SDL_UnlockSurface(diffuse);
+}
+
+#endif
diff --git a/guilib/GUITextureSDL.h b/guilib/GUITextureSDL.h
new file mode 100644
index 0000000000..13d17d3eb3
--- /dev/null
+++ b/guilib/GUITextureSDL.h
@@ -0,0 +1,67 @@
+/*!
+\file GUITextureSDL.h
+\brief
+*/
+
+#ifndef GUILIB_GUITEXTURESDL_H
+#define GUILIB_GUITEXTURESDL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUITexture.h"
+
+#ifdef HAS_SDL_2D
+
+class CCachedTexture
+{
+ public:
+ CCachedTexture() { surface = NULL; width = height = 0; diffuseColor = 0xffffffff; };
+
+ SDL_Surface *surface;
+ int width;
+ int height;
+ color_t diffuseColor;
+};
+
+
+class CGUITextureSDL : public CGUITextureBase
+{
+public:
+ CGUITextureSDL(float posX, float posY, float width, float height, const CTextureInfo& texture);
+ static void DrawQuad(const CRect &rect, color_t color) {};
+protected:
+ void Draw(float *x, float *y, float *z, const CRect &texture, const CRect &diffuse, color_t color, int orientation);
+ virtual void Allocate();
+ virtual void Free();
+
+ void CalcBoundingBox(float *x, float *y, int n, int *b);
+ void GetTexel(float u, float v, SDL_Surface *src, BYTE *texel);
+ void RenderWithEffects(SDL_Surface *src, float *x, float *y, float *u, float *v, color_t *c, SDL_Surface *diffuse, float diffuseScaleU, float diffuseScaleV, CCachedTexture &dst);
+
+ std::vector <CCachedTexture> m_cachedTextures;
+};
+
+#endif
+
+#endif
diff --git a/guilib/GUIToggleButtonControl.cpp b/guilib/GUIToggleButtonControl.cpp
new file mode 100644
index 0000000000..0cb79b4ad2
--- /dev/null
+++ b/guilib/GUIToggleButtonControl.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIToggleButtonControl.h"
+#include "GUIWindowManager.h"
+#include "GUIDialog.h"
+#include "utils/CharsetConverter.h"
+#include "utils/GUIInfoManager.h"
+
+using namespace std;
+
+CGUIToggleButtonControl::CGUIToggleButtonControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus, const CTextureInfo& altTextureFocus, const CTextureInfo& altTextureNoFocus, const CLabelInfo &labelInfo)
+ : CGUIButtonControl(parentID, controlID, posX, posY, width, height, textureFocus, textureNoFocus, labelInfo)
+ , m_selectButton(parentID, controlID, posX, posY, width, height, altTextureFocus, altTextureNoFocus, labelInfo)
+{
+ m_toggleSelect = 0;
+ ControlType = GUICONTROL_TOGGLEBUTTON;
+}
+
+CGUIToggleButtonControl::~CGUIToggleButtonControl(void)
+{
+}
+
+void CGUIToggleButtonControl::Render()
+{
+ // ask our infoManager whether we are selected or not...
+ if (m_toggleSelect)
+ m_bSelected = g_infoManager.GetBool(m_toggleSelect, m_parentID);
+
+ if (m_bSelected)
+ {
+ // render our Alternate textures...
+ m_selectButton.SetFocus(HasFocus());
+ m_selectButton.SetVisible(IsVisible());
+ m_selectButton.SetEnabled(!IsDisabled());
+ m_selectButton.SetPulseOnSelect(m_pulseOnSelect);
+ m_selectButton.Render();
+ CGUIControl::Render();
+ }
+ else
+ { // render our Normal textures...
+ CGUIButtonControl::Render();
+ }
+}
+
+bool CGUIToggleButtonControl::OnAction(const CAction &action)
+{
+ if (action.id == ACTION_SELECT_ITEM)
+ {
+ m_bSelected = !m_bSelected;
+ }
+ return CGUIButtonControl::OnAction(action);
+}
+
+void CGUIToggleButtonControl::AllocResources()
+{
+ CGUIButtonControl::AllocResources();
+ m_selectButton.AllocResources();
+}
+
+void CGUIToggleButtonControl::FreeResources()
+{
+ CGUIButtonControl::FreeResources();
+ m_selectButton.FreeResources();
+}
+
+void CGUIToggleButtonControl::DynamicResourceAlloc(bool bOnOff)
+{
+ CGUIButtonControl::DynamicResourceAlloc(bOnOff);
+ m_selectButton.DynamicResourceAlloc(bOnOff);
+}
+
+void CGUIToggleButtonControl::SetInvalid()
+{
+ CGUIButtonControl::SetInvalid();
+ m_selectButton.SetInvalid();
+}
+
+void CGUIToggleButtonControl::SetPosition(float posX, float posY)
+{
+ CGUIButtonControl::SetPosition(posX, posY);
+ m_selectButton.SetPosition(posX, posY);
+}
+
+void CGUIToggleButtonControl::SetWidth(float width)
+{
+ CGUIButtonControl::SetWidth(width);
+ m_selectButton.SetWidth(width);
+}
+
+void CGUIToggleButtonControl::SetHeight(float height)
+{
+ CGUIButtonControl::SetHeight(height);
+ m_selectButton.SetHeight(height);
+}
+
+void CGUIToggleButtonControl::UpdateColors()
+{
+ CGUIButtonControl::UpdateColors();
+ m_selectButton.UpdateColors();
+}
+
+void CGUIToggleButtonControl::SetLabel(const string &strLabel)
+{
+ CGUIButtonControl::SetLabel(strLabel);
+ m_selectButton.SetLabel(strLabel);
+}
+
+void CGUIToggleButtonControl::SetAltLabel(const string &label)
+{
+ if (label.size())
+ m_selectButton.SetLabel(label);
+}
+
+CStdString CGUIToggleButtonControl::GetLabel() const
+{
+ if (m_bSelected)
+ return m_selectButton.GetLabel();
+ return CGUIButtonControl::GetLabel();
+}
+
+void CGUIToggleButtonControl::SetAltClickActions(const vector<CGUIActionDescriptor> &clickActions)
+{
+ m_selectButton.SetClickActions(clickActions);
+}
+
+void CGUIToggleButtonControl::OnClick()
+{
+ // the ! is here as m_bSelected gets updated before this is called
+ if (!m_bSelected && m_selectButton.HasClickActions())
+ m_selectButton.OnClick();
+ else
+ CGUIButtonControl::OnClick();
+}
diff --git a/guilib/GUIToggleButtonControl.h b/guilib/GUIToggleButtonControl.h
new file mode 100644
index 0000000000..177ddd057f
--- /dev/null
+++ b/guilib/GUIToggleButtonControl.h
@@ -0,0 +1,66 @@
+/*!
+\file GUIToggleButtonControl.h
+\brief
+*/
+
+#ifndef GUILIB_GUITOGGLEBUTTONCONTROL_H
+#define GUILIB_GUITOGGLEBUTTONCONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIButtonControl.h"
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIToggleButtonControl : public CGUIButtonControl
+{
+public:
+ CGUIToggleButtonControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus, const CTextureInfo& altTextureFocus, const CTextureInfo& altTextureNoFocus, const CLabelInfo &labelInfo);
+ virtual ~CGUIToggleButtonControl(void);
+ virtual CGUIToggleButtonControl *Clone() const { return new CGUIToggleButtonControl(*this); };
+
+ virtual void Render();
+ virtual bool OnAction(const CAction &action);
+ virtual void AllocResources();
+ virtual void FreeResources();
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual void SetPosition(float posX, float posY);
+ virtual void SetWidth(float width);
+ virtual void SetHeight(float height);
+ void SetLabel(const std::string& strLabel);
+ void SetAltLabel(const std::string& label);
+ virtual CStdString GetLabel() const;
+ void SetToggleSelect(int toggleSelect) { m_toggleSelect = toggleSelect; };
+ void SetAltClickActions(const std::vector<CGUIActionDescriptor> &clickActions);
+
+protected:
+ virtual void UpdateColors();
+ virtual void OnClick();
+ virtual void SetInvalid();
+ CGUIButtonControl m_selectButton;
+ int m_toggleSelect;
+};
+#endif
diff --git a/guilib/GUIVideoControl.cpp b/guilib/GUIVideoControl.cpp
new file mode 100644
index 0000000000..3a0f9cccac
--- /dev/null
+++ b/guilib/GUIVideoControl.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "GUIVideoControl.h"
+#include "GUIWindowManager.h"
+#include "MouseStat.h"
+#include "Application.h"
+#ifdef HAS_VIDEO_PLAYBACK
+#include "cores/VideoRenderers/RenderManager.h"
+#else
+#include "cores/DummyVideoPlayer.h"
+#endif
+
+CGUIVideoControl::CGUIVideoControl(int parentID, int controlID, float posX, float posY, float width, float height)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+{
+ ControlType = GUICONTROL_VIDEO;
+}
+
+CGUIVideoControl::~CGUIVideoControl(void)
+{}
+
+
+void CGUIVideoControl::Render()
+{
+#ifdef HAS_VIDEO_PLAYBACK
+ // don't render if we aren't playing video, or if the renderer isn't started
+ // (otherwise the lock we have from CApplication::Render() may clash with the startup
+ // locks in the RenderManager.)
+ if (g_application.IsPlayingVideo() && g_renderManager.IsStarted())
+ {
+#else
+ if (g_application.IsPlayingVideo())
+ {
+#endif
+ if (!g_application.m_pPlayer->IsPaused())
+ g_application.ResetScreenSaver();
+
+ g_graphicsContext.SetViewWindow(m_posX, m_posY, m_posX + m_width, m_posY + m_height);
+
+#ifdef HAS_VIDEO_PLAYBACK
+ color_t alpha = g_graphicsContext.MergeAlpha(0xFF000000) >> 24;
+ g_renderManager.RenderUpdate(false, 0, alpha);
+#else
+ ((CDummyVideoPlayer *)g_application.m_pPlayer)->Render();
+#endif
+ }
+ CGUIControl::Render();
+}
+
+bool CGUIVideoControl::OnMouseClick(int button, const CPoint &point)
+{ // mouse has clicked in the video control
+ // switch to fullscreen video
+ if (!g_application.IsPlayingVideo()) return false;
+ if (button == MOUSE_LEFT_BUTTON)
+ {
+ CGUIMessage message(GUI_MSG_FULLSCREEN, GetID(), GetParentID());
+ g_graphicsContext.SendMessage(message);
+ return true;
+ }
+ if (button == MOUSE_RIGHT_BUTTON)
+ { // toggle the playlist window
+ if (m_gWindowManager.GetActiveWindow() == WINDOW_VIDEO_PLAYLIST)
+ m_gWindowManager.PreviousWindow();
+ else
+ m_gWindowManager.ActivateWindow(WINDOW_VIDEO_PLAYLIST);
+ // reset the mouse button.
+ g_Mouse.bClick[MOUSE_RIGHT_BUTTON] = false;
+ return true;
+ }
+ return false;
+}
+
+bool CGUIVideoControl::OnMouseOver(const CPoint &point)
+{
+ // unfocusable, so return true
+ CGUIControl::OnMouseOver(point);
+ return false;
+}
+
+bool CGUIVideoControl::CanFocus() const
+{ // unfocusable
+ return false;
+}
+
+bool CGUIVideoControl::CanFocusFromPoint(const CPoint &point, CGUIControl **control, CPoint &controlPoint) const
+{ // mouse is allowed to focus this control, but it doesn't actually receive focus
+ controlPoint = point;
+ m_transform.InverseTransformPosition(controlPoint.x, controlPoint.y);
+ if (HitTest(controlPoint))
+ {
+ *control = (CGUIControl *)this;
+ return true;
+ }
+ *control = NULL;
+ return false;
+}
diff --git a/guilib/GUIVideoControl.h b/guilib/GUIVideoControl.h
new file mode 100644
index 0000000000..ef82527b66
--- /dev/null
+++ b/guilib/GUIVideoControl.h
@@ -0,0 +1,52 @@
+/*!
+\file GUIVideoControl.h
+\brief
+*/
+
+#ifndef GUILIB_GUIVIDEOCONTROL_H
+#define GUILIB_GUIVIDEOCONTROL_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIVideoControl :
+ public CGUIControl
+{
+public:
+ CGUIVideoControl(int parentID, int controlID, float posX, float posY, float width, float height);
+ virtual ~CGUIVideoControl(void);
+ virtual CGUIVideoControl *Clone() const { return new CGUIVideoControl(*this); };
+
+ virtual void Render();
+ virtual bool OnMouseClick(int button, const CPoint &point);
+ virtual bool OnMouseOver(const CPoint &point);
+ virtual bool CanFocus() const;
+ virtual bool CanFocusFromPoint(const CPoint &point, CGUIControl **control, CPoint &controlPoint) const;
+};
+#endif
diff --git a/guilib/GUIVisualisationControl.cpp b/guilib/GUIVisualisationControl.cpp
new file mode 100644
index 0000000000..acd7554147
--- /dev/null
+++ b/guilib/GUIVisualisationControl.cpp
@@ -0,0 +1,484 @@
+#include "GUIVisualisationControl.h"
+#include "GUIUserMessages.h"
+#include "Application.h"
+#include "visualizations/Visualisation.h"
+#include "visualizations/VisualisationFactory.h"
+#include "visualizations/fft.h"
+#include "Util.h"
+#include "utils/CriticalSection.h"
+#include "utils/log.h"
+#include "utils/SingleLock.h"
+#include "utils/GUIInfoManager.h"
+#include "GUISettings.h"
+
+using namespace std;
+using namespace MUSIC_INFO;
+
+#define LABEL_ROW1 10
+#define LABEL_ROW2 11
+#define LABEL_ROW3 12
+
+// uggly hack, we can only allow one visualisation at one time or stuff starts crashing
+static CCriticalSection m_critSection;
+static bool m_globalvis = false;
+
+CAudioBuffer::CAudioBuffer(int iSize)
+{
+ m_iLen = iSize;
+ m_pBuffer = new short[iSize];
+}
+
+CAudioBuffer::~CAudioBuffer()
+{
+ delete [] m_pBuffer;
+}
+
+const short* CAudioBuffer::Get() const
+{
+ return m_pBuffer;
+}
+
+void CAudioBuffer::Set(const unsigned char* psBuffer, int iSize, int iBitsPerSample)
+{
+ if (iSize<0)
+ {
+ return;
+ }
+
+ if (iBitsPerSample == 16)
+ {
+ iSize /= 2;
+ for (int i = 0; i < iSize && i < m_iLen; i++)
+ { // 16 bit -> convert to short directly
+ m_pBuffer[i] = ((short *)psBuffer)[i];
+ }
+ }
+ else if (iBitsPerSample == 8)
+ {
+ for (int i = 0; i < iSize && i < m_iLen; i++)
+ { // 8 bit -> convert to signed short by multiplying by 256
+ m_pBuffer[i] = ((short)((char *)psBuffer)[i]) << 8;
+ }
+ }
+ else // assume 24 bit data
+ {
+ iSize /= 3;
+ for (int i = 0; i < iSize && i < m_iLen; i++)
+ { // 24 bit -> ignore least significant byte and convert to signed short
+ m_pBuffer[i] = (((int)psBuffer[3 * i + 1]) << 0) + (((int)((char *)psBuffer)[3 * i + 2]) << 8);
+ }
+ }
+ for (int i = iSize; i < m_iLen;++i) m_pBuffer[i] = 0;
+}
+
+CGUIVisualisationControl::CGUIVisualisationControl(int parentID, int controlID, float posX, float posY, float width, float height)
+ : CGUIControl(parentID, controlID, posX, posY, width, height)
+{
+ m_pVisualisation = NULL;
+ m_bInitialized = false;
+ m_iNumBuffers = 0;
+ m_currentVis = "";
+ ControlType = GUICONTROL_VISUALISATION;
+}
+
+CGUIVisualisationControl::CGUIVisualisationControl(const CGUIVisualisationControl &from)
+: CGUIControl(from)
+{
+ m_pVisualisation = NULL;
+ m_bInitialized = false;
+ m_iNumBuffers = 0;
+ m_currentVis = "";
+ ControlType = GUICONTROL_VISUALISATION;
+}
+
+CGUIVisualisationControl::~CGUIVisualisationControl(void)
+{
+}
+
+void CGUIVisualisationControl::FreeVisualisation()
+{
+ if (!m_bInitialized) return;
+ m_bInitialized = false;
+ // tell our app that we're going
+ CGUIMessage msg(GUI_MSG_VISUALISATION_UNLOADING, 0, 0);
+ g_graphicsContext.SendMessage(msg);
+
+ CSingleLock lock (m_critSection);
+
+ CLog::Log(LOGDEBUG, "FreeVisualisation() started");
+ if (g_application.m_pPlayer)
+ g_application.m_pPlayer->UnRegisterAudioCallback();
+ if (m_pVisualisation)
+ {
+ OutputDebugString("Visualisation::Stop()\n");
+ g_graphicsContext.CaptureStateBlock();
+ m_pVisualisation->Stop();
+ g_graphicsContext.ApplyStateBlock();
+
+ OutputDebugString("delete Visualisation()\n");
+ delete m_pVisualisation;
+
+ /* we released the global vis spot */
+ m_globalvis = false;
+ }
+ m_pVisualisation = NULL;
+ ClearBuffers();
+ CLog::Log(LOGDEBUG, "FreeVisualisation() done");
+}
+
+void CGUIVisualisationControl::LoadVisualisation()
+{
+ CSingleLock lock (m_critSection);
+ if (m_pVisualisation)
+ FreeVisualisation();
+
+ m_bInitialized = false;
+
+ /* check if any other control beat us to the punch */
+ if(m_globalvis)
+ return;
+
+ CVisualisationFactory factory;
+ CStdString strVisz, strModule;
+ m_currentVis = g_guiSettings.GetString("mymusic.visualisation");
+
+ if (m_currentVis.Equals("None"))
+ return;
+
+ // check if it's a multi-vis and if it is , get it's module name
+ {
+ int colonPos = m_currentVis.ReverseFind(":");
+ if ( colonPos > 0 )
+ {
+ strModule = m_currentVis.Mid( colonPos+1 );
+ strVisz = m_currentVis.Mid( 0, colonPos );
+ m_pVisualisation = factory.LoadVisualisation(strVisz, strModule);
+ }
+ else
+ {
+ strVisz = m_currentVis;
+ m_pVisualisation = factory.LoadVisualisation(strVisz);
+ }
+ }
+ if (m_pVisualisation)
+ {
+ g_graphicsContext.CaptureStateBlock();
+ float x = g_graphicsContext.ScaleFinalXCoord(GetXPosition(), GetYPosition());
+ float y = g_graphicsContext.ScaleFinalYCoord(GetXPosition(), GetYPosition());
+ float w = g_graphicsContext.ScaleFinalXCoord(GetXPosition() + GetWidth(), GetYPosition() + GetHeight()) - x;
+ float h = g_graphicsContext.ScaleFinalYCoord(GetXPosition() + GetWidth(), GetYPosition() + GetHeight()) - y;
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+ if (x + w > g_graphicsContext.GetWidth()) w = g_graphicsContext.GetWidth() - x;
+ if (y + h > g_graphicsContext.GetHeight()) h = g_graphicsContext.GetHeight() - y;
+
+ m_pVisualisation->Create((int)(x+0.5f), (int)(y+0.5f), (int)(w+0.5f), (int)(h+0.5f));
+ g_graphicsContext.ApplyStateBlock();
+ VerifyGLState();
+ if (g_application.m_pPlayer)
+ g_application.m_pPlayer->RegisterAudioCallback(this);
+
+ // Create new audio buffers
+ CreateBuffers();
+
+ m_globalvis = true;
+ }
+
+ // tell our app that we're back
+ CGUIMessage msg(GUI_MSG_VISUALISATION_LOADED, 0, 0, 0, 0, m_pVisualisation);
+ g_graphicsContext.SendMessage(msg);
+}
+
+void CGUIVisualisationControl::UpdateVisibility(const CGUIListItem *item)
+{
+ CGUIControl::UpdateVisibility(item);
+ if (!IsVisible() && m_bInitialized)
+ FreeVisualisation();
+}
+
+void CGUIVisualisationControl::Render()
+{
+ if (m_pVisualisation == NULL)
+ { // check if we need to load
+ if (g_application.IsPlayingAudio())
+ {
+ LoadVisualisation();
+ }
+ CGUIControl::Render();
+
+ return;
+ }
+ else
+ { // check if we need to unload
+ if (!g_application.IsPlayingAudio())
+ { // deinit
+ FreeVisualisation();
+ CGUIControl::Render();
+ return;
+ }
+ else if (!m_currentVis.Equals(g_guiSettings.GetString("mymusic.visualisation")))
+ { // vis changed - reload
+ LoadVisualisation();
+
+ CGUIControl::Render();
+
+ return;
+ }
+ }
+ CSingleLock lock (m_critSection);
+ if (m_pVisualisation)
+ {
+ if (m_bInitialized)
+ {
+ // set the viewport - note: We currently don't have any control over how
+ // the visualisation renders, so the best we can do is attempt to define
+ // a viewport??
+ g_graphicsContext.SetViewPort(m_posX, m_posY, m_width, m_height);
+ try
+ {
+ g_graphicsContext.CaptureStateBlock();
+ m_pVisualisation->Render();
+ g_graphicsContext.ApplyStateBlock();
+ }
+ catch (...)
+ {
+ CLog::Log(LOGERROR, "Exception in Visualisation::Render()");
+ }
+ // clear the viewport
+ g_graphicsContext.RestoreViewPort();
+ }
+ }
+
+ CGUIControl::Render();
+}
+
+
+void CGUIVisualisationControl::OnInitialize(int iChannels, int iSamplesPerSec, int iBitsPerSample)
+{
+ CSingleLock lock (m_critSection);
+ if (!m_pVisualisation)
+ return ;
+ CLog::Log(LOGDEBUG, "OnInitialize() started");
+
+ m_iChannels = iChannels;
+ m_iSamplesPerSec = iSamplesPerSec;
+ m_iBitsPerSample = iBitsPerSample;
+
+ // Start the visualisation (this loads settings etc.)
+ CStdString strFile = CUtil::GetFileName(g_application.CurrentFile());
+ OutputDebugString("Visualisation::Start()\n");
+ m_pVisualisation->Start(m_iChannels, m_iSamplesPerSec, m_iBitsPerSample, strFile);
+ if (!m_bInitialized)
+ {
+ UpdateTrack();
+ }
+ m_bInitialized = true;
+ CLog::Log(LOGDEBUG, "OnInitialize() done");
+}
+
+void CGUIVisualisationControl::OnAudioData(const unsigned char* pAudioData, int iAudioDataLength)
+{
+ CSingleLock lock (m_critSection);
+ if (!m_pVisualisation)
+ return ;
+ if (!m_bInitialized) return ;
+
+ // FIXME: iAudioDataLength should never be less than 0
+ if (iAudioDataLength<0)
+ return;
+
+ // Save our audio data in the buffers
+ auto_ptr<CAudioBuffer> pBuffer ( new CAudioBuffer(2*AUDIO_BUFFER_SIZE) );
+ pBuffer->Set(pAudioData, iAudioDataLength, m_iBitsPerSample);
+ m_vecBuffers.push_back( pBuffer.release() );
+
+ if ( (int)m_vecBuffers.size() < m_iNumBuffers) return ;
+
+ auto_ptr<CAudioBuffer> ptrAudioBuffer ( m_vecBuffers.front() );
+ m_vecBuffers.pop_front();
+ // Fourier transform the data if the vis wants it...
+ if (m_bWantsFreq)
+ {
+ // Convert to floats
+ const short* psAudioData = ptrAudioBuffer->Get();
+ for (int i = 0; i < 2*AUDIO_BUFFER_SIZE; i++)
+ {
+ m_fFreq[i] = (float)psAudioData[i];
+ }
+
+ // FFT the data
+ twochanwithwindow(m_fFreq, AUDIO_BUFFER_SIZE);
+
+ // Normalize the data
+ float fMinData = (float)AUDIO_BUFFER_SIZE * AUDIO_BUFFER_SIZE * 3 / 8 * 0.5 * 0.5; // 3/8 for the Hann window, 0.5 as minimum amplitude
+ float fInvMinData = 1.0f/fMinData;
+ for (int i = 0; i < AUDIO_BUFFER_SIZE + 2; i++)
+ {
+ m_fFreq[i] *= fInvMinData;
+ }
+
+ // Transfer data to our visualisation
+ try
+ {
+ m_pVisualisation->AudioData(ptrAudioBuffer->Get(), AUDIO_BUFFER_SIZE, m_fFreq, AUDIO_BUFFER_SIZE);
+ }
+ catch (...)
+ {
+ CLog::Log(LOGERROR, "Exception in Visualisation::AudioData()");
+ }
+ }
+ else
+ { // Transfer data to our visualisation
+ try
+ {
+ m_pVisualisation->AudioData(ptrAudioBuffer->Get(), AUDIO_BUFFER_SIZE, NULL, 0);
+ }
+ catch (...)
+ {
+ CLog::Log(LOGERROR, "Exception in Visualisation::AudioData()");
+ }
+ }
+ return ;
+}
+
+bool CGUIVisualisationControl::OnAction(const CAction &action)
+{
+ if (!m_pVisualisation) return false;
+ enum CVisualisation::VIS_ACTION visAction = CVisualisation::VIS_ACTION_NONE;
+ if (action.id == ACTION_VIS_PRESET_NEXT)
+ visAction = CVisualisation::VIS_ACTION_NEXT_PRESET;
+ else if (action.id == ACTION_VIS_PRESET_PREV)
+ visAction = CVisualisation::VIS_ACTION_PREV_PRESET;
+ else if (action.id == ACTION_VIS_PRESET_LOCK)
+ visAction = CVisualisation::VIS_ACTION_LOCK_PRESET;
+ else if (action.id == ACTION_VIS_PRESET_RANDOM)
+ visAction = CVisualisation::VIS_ACTION_RANDOM_PRESET;
+ else if (action.id == ACTION_VIS_RATE_PRESET_PLUS)
+ visAction = CVisualisation::VIS_ACTION_RATE_PRESET_PLUS;
+ else if (action.id == ACTION_VIS_RATE_PRESET_MINUS)
+ visAction = CVisualisation::VIS_ACTION_RATE_PRESET_MINUS;
+
+ return m_pVisualisation->OnAction(visAction);
+}
+
+bool CGUIVisualisationControl::UpdateTrack()
+{
+ bool handled = false;
+
+ if ( m_pVisualisation )
+ {
+ // get the current album art filename
+ m_AlbumThumb = g_infoManager.GetImage(MUSICPLAYER_COVER, WINDOW_INVALID);
+
+ // get the current track tag
+ const CMusicInfoTag* tag = g_infoManager.GetCurrentSongTag();
+
+ if (m_AlbumThumb == "DefaultAlbumCover.png")
+ m_AlbumThumb = "";
+ else
+ CLog::Log(LOGDEBUG,"Updating visualisation albumart: %s", m_AlbumThumb.c_str());
+
+ // inform the visulisation of the current album art
+ if ( m_pVisualisation->OnAction( CVisualisation::VIS_ACTION_UPDATE_ALBUMART,
+ (void*)( m_AlbumThumb.c_str() ) ) )
+ handled = true;
+
+ // inform the visualisation of the current track's tag information
+ if ( tag && m_pVisualisation->OnAction( CVisualisation::VIS_ACTION_UPDATE_TRACK,
+ (void*)tag ) )
+ handled = true;
+ }
+ return handled;
+}
+
+bool CGUIVisualisationControl::OnMessage(CGUIMessage &message)
+{
+ if (message.GetMessage() == GUI_MSG_GET_VISUALISATION)
+ {
+ message.SetPointer(GetVisualisation());
+ return true;
+ }
+ else if (message.GetMessage() == GUI_MSG_VISUALISATION_ACTION)
+ {
+ CAction action;
+ action.id = message.GetParam1();
+ return OnAction(action);
+ }
+ else if (message.GetMessage() == GUI_MSG_PLAYBACK_STARTED)
+ {
+ if (IsVisible() && UpdateTrack()) return true;
+ }
+ return CGUIControl::OnMessage(message);
+}
+
+void CGUIVisualisationControl::CreateBuffers()
+{
+ CSingleLock lock (m_critSection);
+ ClearBuffers();
+
+ // Get the number of buffers from the current vis
+ VIS_INFO info;
+ m_pVisualisation->GetInfo(&info);
+ m_iNumBuffers = info.iSyncDelay + 1;
+ m_bWantsFreq = info.bWantsFreq;
+ if (m_iNumBuffers > MAX_AUDIO_BUFFERS)
+ m_iNumBuffers = MAX_AUDIO_BUFFERS;
+ if (m_iNumBuffers < 1)
+ m_iNumBuffers = 1;
+}
+
+
+void CGUIVisualisationControl::ClearBuffers()
+{
+ CSingleLock lock (m_critSection);
+ m_bWantsFreq = false;
+ m_iNumBuffers = 0;
+
+ while (m_vecBuffers.size() > 0)
+ {
+ CAudioBuffer* pAudioBuffer = m_vecBuffers.front();
+ delete pAudioBuffer;
+ m_vecBuffers.pop_front();
+ }
+ for (int j = 0; j < AUDIO_BUFFER_SIZE*2; j++)
+ {
+ m_fFreq[j] = 0.0f;
+ }
+}
+
+void CGUIVisualisationControl::FreeResources()
+{
+ FreeVisualisation();
+ CGUIControl::FreeResources();
+}
+
+CVisualisation *CGUIVisualisationControl::GetVisualisation()
+{
+ CSingleLock lock (m_critSection);
+ return m_pVisualisation;
+}
+
+bool CGUIVisualisationControl::OnMouseOver(const CPoint &point)
+{
+ // unfocusable, so return true
+ CGUIControl::OnMouseOver(point);
+ return false;
+}
+
+bool CGUIVisualisationControl::CanFocus() const
+{ // unfocusable
+ return false;
+}
+
+bool CGUIVisualisationControl::CanFocusFromPoint(const CPoint &point, CGUIControl **control, CPoint &controlPoint) const
+{ // mouse is allowed to focus this control, but it doesn't actually receive focus
+ controlPoint = point;
+ m_transform.InverseTransformPosition(controlPoint.x, controlPoint.y);
+ if (HitTest(controlPoint))
+ {
+ *control = (CGUIControl *)this;
+ return true;
+ }
+ *control = NULL;
+ return false;
+}
diff --git a/guilib/GUIVisualisationControl.h b/guilib/GUIVisualisationControl.h
new file mode 100644
index 0000000000..1d73337969
--- /dev/null
+++ b/guilib/GUIVisualisationControl.h
@@ -0,0 +1,88 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControl.h"
+#include "cores/IAudioCallback.h"
+
+#include <list>
+
+// forward definitions
+class CVisualisation;
+
+#define AUDIO_BUFFER_SIZE 512 // MUST BE A POWER OF 2!!!
+#define MAX_AUDIO_BUFFERS 16
+
+class CAudioBuffer
+{
+public:
+ CAudioBuffer(int iSize);
+ virtual ~CAudioBuffer();
+ const short* Get() const;
+ void Set(const unsigned char* psBuffer, int iSize, int iBitsPerSample);
+private:
+ CAudioBuffer();
+ short* m_pBuffer;
+ int m_iLen;
+};
+
+class CGUIVisualisationControl :
+ public CGUIControl, public IAudioCallback
+{
+public:
+ CGUIVisualisationControl(int parentID, int controlID, float posX, float posY, float width, float height);
+ CGUIVisualisationControl(const CGUIVisualisationControl &from);
+ virtual ~CGUIVisualisationControl(void);
+ virtual CGUIVisualisationControl *Clone() const { return new CGUIVisualisationControl(*this); };
+
+ virtual void Render();
+ virtual void UpdateVisibility(const CGUIListItem *item = NULL);
+ virtual void FreeResources();
+ virtual void OnInitialize(int iChannels, int iSamplesPerSec, int iBitsPerSample);
+ virtual void OnAudioData(const unsigned char* pAudioData, int iAudioDataLength);
+ virtual bool OnAction(const CAction &action);
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual bool OnMouseOver(const CPoint &point);
+ virtual bool CanFocus() const;
+ virtual bool CanFocusFromPoint(const CPoint &point, CGUIControl **control, CPoint &controlPoint) const;
+
+ CVisualisation *GetVisualisation();
+private:
+ void FreeVisualisation();
+ void LoadVisualisation();
+ void CreateBuffers();
+ void ClearBuffers();
+ bool UpdateTrack();
+ CStdString m_currentVis;
+ CVisualisation* m_pVisualisation;
+
+ int m_iChannels;
+ int m_iSamplesPerSec;
+ int m_iBitsPerSample;
+ std::list<CAudioBuffer*> m_vecBuffers;
+ int m_iNumBuffers; // Number of Audio buffers
+ bool m_bWantsFreq;
+ float m_fFreq[2*AUDIO_BUFFER_SIZE]; // Frequency data
+ bool m_bCalculate_Freq; // True if the vis wants freq data
+ bool m_bInitialized;
+ CStdString m_AlbumThumb;
+};
diff --git a/guilib/GUIWindow.cpp b/guilib/GUIWindow.cpp
new file mode 100644
index 0000000000..30c7a90b7f
--- /dev/null
+++ b/guilib/GUIWindow.cpp
@@ -0,0 +1,1022 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "GUIWindow.h"
+#include "GUIWindowManager.h"
+#include "Key.h"
+#include "LocalizeStrings.h"
+#include "Settings.h"
+#include "GUIControlFactory.h"
+#include "GUIControlGroup.h"
+#include "GUIControlProfiler.h"
+#ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY
+#include "GUIEditControl.h"
+#endif
+
+#include "SkinInfo.h"
+#include "utils/GUIInfoManager.h"
+#include "utils/log.h"
+#include "utils/SingleLock.h"
+#include "ButtonTranslator.h"
+#include "XMLUtils.h"
+#include "MouseStat.h"
+
+#ifdef HAS_PERFORMANCE_SAMPLE
+#include "utils/PerformanceSample.h"
+#endif
+
+using namespace std;
+
+CGUIWindow::CGUIWindow(int id, const CStdString &xmlFile)
+{
+ SetID(id);
+ m_xmlFile = xmlFile;
+ m_idRange = 1;
+ m_lastControlID = 0;
+ m_bRelativeCoords = false;
+ m_overlayState = OVERLAY_STATE_PARENT_WINDOW; // Use parent or previous window's state
+ m_coordsRes = g_guiSettings.m_LookAndFeelResolution;
+ m_isDialog = false;
+ m_needsScaling = true;
+ m_windowLoaded = false;
+ m_loadOnDemand = true;
+ m_renderOrder = 0;
+ m_dynamicResourceAlloc = true;
+ m_previousWindow = WINDOW_INVALID;
+ m_animationsEnabled = true;
+ m_manualRunActions = false;
+}
+
+CGUIWindow::~CGUIWindow(void)
+{}
+
+bool CGUIWindow::Load(const CStdString& strFileName, bool bContainsPath)
+{
+#ifdef HAS_PERFORMANCE_SAMPLE
+ CPerformanceSample aSample("WindowLoad-" + strFileName, true);
+#endif
+
+ if (m_windowLoaded)
+ return true; // no point loading if it's already there
+
+ LARGE_INTEGER start;
+ QueryPerformanceCounter(&start);
+
+ RESOLUTION resToUse = RES_INVALID;
+ CLog::Log(LOGINFO, "Loading skin file: %s", strFileName.c_str());
+ TiXmlDocument xmlDoc;
+ // Find appropriate skin folder + resolution to load from
+ CStdString strPath;
+ CStdString strLowerPath;
+ if (bContainsPath)
+ strPath = strFileName;
+ else
+ {
+ // FIXME: strLowerPath needs to eventually go since resToUse can get incorrectly overridden
+ strLowerPath = g_SkinInfo.GetSkinPath(CStdString(strFileName).ToLower(), &resToUse);
+ strPath = g_SkinInfo.GetSkinPath(strFileName, &resToUse);
+ }
+
+ if (!bContainsPath)
+ m_coordsRes = resToUse;
+
+ bool ret = LoadXML(strPath.c_str(), strLowerPath.c_str());
+
+ LARGE_INTEGER end, freq;
+ QueryPerformanceCounter(&end);
+ QueryPerformanceFrequency(&freq);
+ CLog::Log(LOGDEBUG,"Load %s: %.2fms", m_xmlFile.c_str(), 1000.f * (end.QuadPart - start.QuadPart) / freq.QuadPart);
+
+ return ret;
+}
+
+bool CGUIWindow::LoadXML(const CStdString &strPath, const CStdString &strLowerPath)
+{
+ TiXmlDocument xmlDoc;
+ if ( !xmlDoc.LoadFile(strPath) && !xmlDoc.LoadFile(CStdString(strPath).ToLower()) && !xmlDoc.LoadFile(strLowerPath))
+ {
+ CLog::Log(LOGERROR, "unable to load:%s, Line %d\n%s", strPath.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
+ SetID(WINDOW_INVALID);
+ return false;
+ }
+
+ return Load(xmlDoc);
+}
+
+bool CGUIWindow::Load(TiXmlDocument &xmlDoc)
+{
+ TiXmlElement* pRootElement = xmlDoc.RootElement();
+ if (strcmpi(pRootElement->Value(), "window"))
+ {
+ CLog::Log(LOGERROR, "file : XML file doesnt contain <window>");
+ return false;
+ }
+
+ // set the scaling resolution so that any control creation or initialisation can
+ // be done with respect to the correct aspect ratio
+ g_graphicsContext.SetScalingResolution(m_coordsRes, 0, 0, m_needsScaling);
+
+ // Resolve any includes that may be present
+ g_SkinInfo.ResolveIncludes(pRootElement);
+ // now load in the skin file
+ SetDefaults();
+
+
+ CGUIControlFactory::GetMultipleString(pRootElement, "onload", m_loadActions);
+ CGUIControlFactory::GetMultipleString(pRootElement, "onunload", m_unloadActions);
+
+ TiXmlElement *pChild = pRootElement->FirstChildElement();
+ while (pChild)
+ {
+ CStdString strValue = pChild->Value();
+ if (strValue == "type" && pChild->FirstChild())
+ {
+ // if we have are a window type (ie not a dialog), and we have <type>dialog</type>
+ // then make this window act like a dialog
+ if (!IsDialog() && strcmpi(pChild->FirstChild()->Value(), "dialog") == 0)
+ m_isDialog = true;
+ }
+ else if (strValue == "previouswindow" && pChild->FirstChild())
+ {
+ m_previousWindow = CButtonTranslator::TranslateWindowString(pChild->FirstChild()->Value());
+ }
+ else if (strValue == "defaultcontrol" && pChild->FirstChild())
+ {
+ const char *always = pChild->Attribute("always");
+ if (always && strcmpi(always, "true") == 0)
+ m_defaultAlways = true;
+ m_defaultControl = atoi(pChild->FirstChild()->Value());
+ }
+ else if (strValue == "visible" && pChild->FirstChild())
+ {
+ CGUIControlFactory::GetConditionalVisibility(pRootElement, m_visibleCondition);
+ }
+ else if (strValue == "animation" && pChild->FirstChild())
+ {
+ FRECT rect = { 0, 0, (float)g_settings.m_ResInfo[m_coordsRes].iWidth, (float)g_settings.m_ResInfo[m_coordsRes].iHeight };
+ CAnimation anim;
+ anim.Create(pChild, rect);
+ m_animations.push_back(anim);
+ }
+ else if (strValue == "zorder" && pChild->FirstChild())
+ {
+ m_renderOrder = atoi(pChild->FirstChild()->Value());
+ }
+ else if (strValue == "coordinates")
+ {
+ // resolve any includes within coordinates tag (such as multiple origin includes)
+ g_SkinInfo.ResolveIncludes(pChild);
+ TiXmlNode* pSystem = pChild->FirstChild("system");
+ if (pSystem)
+ {
+ int iCoordinateSystem = atoi(pSystem->FirstChild()->Value());
+ m_bRelativeCoords = (iCoordinateSystem == 1);
+ }
+
+ CGUIControlFactory::GetFloat(pChild, "posx", m_posX);
+ CGUIControlFactory::GetFloat(pChild, "posy", m_posY);
+
+ TiXmlElement *originElement = pChild->FirstChildElement("origin");
+ while (originElement)
+ {
+ COrigin origin;
+ g_SkinInfo.ResolveConstant(originElement->Attribute("x"), origin.x);
+ g_SkinInfo.ResolveConstant(originElement->Attribute("y"), origin.y);
+ if (originElement->FirstChild())
+ origin.condition = g_infoManager.TranslateString(originElement->FirstChild()->Value());
+ m_origins.push_back(origin);
+ originElement = originElement->NextSiblingElement("origin");
+ }
+ }
+ else if (strValue == "camera")
+ { // z is fixed
+ g_SkinInfo.ResolveConstant(pChild->Attribute("x"), m_camera.x);
+ g_SkinInfo.ResolveConstant(pChild->Attribute("y"), m_camera.y);
+ m_hasCamera = true;
+ }
+ else if (strValue == "controls")
+ {
+ // resolve any includes within controls tag (such as whole <control> includes)
+ g_SkinInfo.ResolveIncludes(pChild);
+
+ TiXmlElement *pControl = pChild->FirstChildElement();
+ while (pControl)
+ {
+ if (strcmpi(pControl->Value(), "control") == 0)
+ {
+ LoadControl(pControl, NULL);
+ }
+ pControl = pControl->NextSiblingElement();
+ }
+ }
+ else if (strValue == "allowoverlay")
+ {
+ bool overlay = false;
+ if (XMLUtils::GetBoolean(pRootElement, "allowoverlay", overlay))
+ m_overlayState = overlay ? OVERLAY_STATE_SHOWN : OVERLAY_STATE_HIDDEN;
+ }
+
+ pChild = pChild->NextSiblingElement();
+ }
+ LoadAdditionalTags(pRootElement);
+
+ m_windowLoaded = true;
+ OnWindowLoaded();
+ return true;
+}
+
+void CGUIWindow::LoadControl(TiXmlElement* pControl, CGUIControlGroup *pGroup)
+{
+ // get control type
+ CGUIControlFactory factory;
+
+ FRECT rect = { 0, 0, (float)g_settings.m_ResInfo[m_coordsRes].iWidth, (float)g_settings.m_ResInfo[m_coordsRes].iHeight };
+ if (pGroup)
+ {
+ rect.left = pGroup->GetXPosition();
+ rect.top = pGroup->GetYPosition();
+ rect.right = rect.left + pGroup->GetWidth();
+ rect.bottom = rect.top + pGroup->GetHeight();
+ }
+ CGUIControl* pGUIControl = factory.Create(GetID(), rect, pControl);
+ if (pGUIControl)
+ {
+ float maxX = pGUIControl->GetXPosition() + pGUIControl->GetWidth();
+ if (maxX > m_width)
+ {
+ m_width = maxX;
+ }
+
+ float maxY = pGUIControl->GetYPosition() + pGUIControl->GetHeight();
+ if (maxY > m_height)
+ {
+ m_height = maxY;
+ }
+ // if we are in a group, add to the group, else add to our window
+ if (pGroup)
+ pGroup->AddControl(pGUIControl);
+ else
+ AddControl(pGUIControl);
+ // if the new control is a group, then add it's controls
+ if (pGUIControl->IsGroup())
+ {
+ TiXmlElement *pSubControl = pControl->FirstChildElement("control");
+ while (pSubControl)
+ {
+ LoadControl(pSubControl, (CGUIControlGroup *)pGUIControl);
+ pSubControl = pSubControl->NextSiblingElement("control");
+ }
+ }
+ }
+}
+
+void CGUIWindow::OnWindowLoaded()
+{
+ DynamicResourceAlloc(true);
+}
+
+void CGUIWindow::CenterWindow()
+{
+ if (m_bRelativeCoords)
+ {
+ m_posX = (g_settings.m_ResInfo[m_coordsRes].iWidth - GetWidth()) / 2;
+ m_posY = (g_settings.m_ResInfo[m_coordsRes].iHeight - GetHeight()) / 2;
+ }
+}
+
+void CGUIWindow::Render()
+{
+ // If we're rendering from a different thread, then we should wait for the main
+ // app thread to finish AllocResources(), as dynamic resources (images in particular)
+ // will try and be allocated from 2 different threads, which causes nasty things
+ // to occur.
+ if (!m_bAllocated) return;
+
+ // find our origin point
+ float posX = m_posX;
+ float posY = m_posY;
+ for (unsigned int i = 0; i < m_origins.size(); i++)
+ {
+ // no condition implies true
+ if (!m_origins[i].condition || g_infoManager.GetBool(m_origins[i].condition, GetID()))
+ { // found origin
+ posX = m_origins[i].x;
+ posY = m_origins[i].y;
+ break;
+ }
+ }
+ g_graphicsContext.SetRenderingResolution(m_coordsRes, posX, posY, m_needsScaling);
+ if (m_hasCamera)
+ g_graphicsContext.SetCameraPosition(m_camera);
+
+ DWORD currentTime = timeGetTime();
+ // render our window animation - returns false if it needs to stop rendering
+ if (!RenderAnimation(currentTime))
+ return;
+
+ for (iControls i = m_children.begin(); i != m_children.end(); ++i)
+ {
+ CGUIControl *pControl = *i;
+ if (pControl)
+ {
+ GUIPROFILER_VISIBILITY_BEGIN(pControl);
+ pControl->UpdateVisibility();
+ GUIPROFILER_VISIBILITY_END(pControl);
+ pControl->DoRender(currentTime);
+ }
+ }
+ if (CGUIControlProfiler::IsRunning()) CGUIControlProfiler::Instance().EndFrame();
+ m_hasRendered = true;
+}
+
+void CGUIWindow::Close(bool forceClose)
+{
+ CLog::Log(LOGERROR,"%s - should never be called on the base class!", __FUNCTION__);
+}
+
+bool CGUIWindow::OnAction(const CAction &action)
+{
+ if (action.id == ACTION_MOUSE)
+ return OnMouseAction();
+
+ CGUIControl *focusedControl = GetFocusedControl();
+ if (focusedControl)
+ return focusedControl->OnAction(action);
+
+ // no control has focus?
+ // set focus to the default control then
+ CGUIMessage msg(GUI_MSG_SETFOCUS, GetID(), m_defaultControl);
+ OnMessage(msg);
+ return false;
+}
+
+// OnMouseAction - called by OnAction()
+bool CGUIWindow::OnMouseAction()
+{
+ // we need to convert the mouse coordinates to window coordinates
+ float posX = m_posX;
+ float posY = m_posY;
+ for (unsigned int i = 0; i < m_origins.size(); i++)
+ {
+ // no condition implies true
+ if (!m_origins[i].condition || g_infoManager.GetBool(m_origins[i].condition, GetID()))
+ { // found origin
+ posX = m_origins[i].x;
+ posY = m_origins[i].y;
+ break;
+ }
+ }
+ g_graphicsContext.SetScalingResolution(m_coordsRes, posX, posY, m_needsScaling);
+ CPoint mousePoint(g_Mouse.GetLocation());
+ g_graphicsContext.InvertFinalCoords(mousePoint.x, mousePoint.y);
+ m_transform.InverseTransformPosition(mousePoint.x, mousePoint.y);
+
+ bool bHandled = false;
+ // check if we have exclusive access
+ if (g_Mouse.GetExclusiveWindowID() == GetID())
+ { // we have exclusive access to the mouse...
+ CGUIControl *pControl = (CGUIControl *)GetControl(g_Mouse.GetExclusiveControlID());
+ if (pControl)
+ { // this control has exclusive access to the mouse
+ HandleMouse(pControl, mousePoint + g_Mouse.GetExclusiveOffset());
+ return true;
+ }
+ }
+
+ // run through the controls, and unfocus all those that aren't under the pointer,
+ for (iControls i = m_children.begin(); i != m_children.end(); ++i)
+ {
+ CGUIControl *pControl = *i;
+ pControl->UnfocusFromPoint(mousePoint);
+ }
+ // and find which one is under the pointer
+ // go through in reverse order to make sure we start with the ones on top
+ bool controlUnderPointer(false);
+ for (vector<CGUIControl *>::reverse_iterator i = m_children.rbegin(); i != m_children.rend(); ++i)
+ {
+ CGUIControl *pControl = *i;
+ CGUIControl *focusableControl = NULL;
+ CPoint controlPoint;
+ if (pControl->CanFocusFromPoint(mousePoint, &focusableControl, controlPoint))
+ {
+ controlUnderPointer = focusableControl->OnMouseOver(controlPoint);
+ bHandled = HandleMouse(focusableControl, controlPoint);
+ if (bHandled || controlUnderPointer)
+ break;
+ }
+ }
+ if (!bHandled)
+ { // haven't handled this action - call the window message handlers
+ bHandled = OnMouse(mousePoint);
+ }
+ // and unfocus everything otherwise
+ if (!controlUnderPointer)
+ m_focusedControl = 0;
+
+ return bHandled;
+}
+
+// Handles any mouse actions that are not handled by a control
+// default is to go back a window on a right click.
+// This function should be overridden for other windows
+bool CGUIWindow::OnMouse(const CPoint &point)
+{
+ if (g_Mouse.bClick[MOUSE_RIGHT_BUTTON])
+ { // no control found to absorb this click - go to previous menu
+ CAction action;
+ action.id = ACTION_PREVIOUS_MENU;
+ return OnAction(action);
+ }
+ return false;
+}
+
+bool CGUIWindow::HandleMouse(CGUIControl *pControl, const CPoint &point)
+{
+ if (g_Mouse.bClick[MOUSE_LEFT_BUTTON])
+ { // Left click
+ return pControl->OnMouseClick(MOUSE_LEFT_BUTTON, point);
+ }
+ else if (g_Mouse.bClick[MOUSE_RIGHT_BUTTON])
+ { // Right click
+ return pControl->OnMouseClick(MOUSE_RIGHT_BUTTON, point);
+ }
+ else if (g_Mouse.bClick[MOUSE_MIDDLE_BUTTON])
+ { // Middle click
+ return pControl->OnMouseClick(MOUSE_MIDDLE_BUTTON, point);
+ }
+ else if (g_Mouse.bDoubleClick[MOUSE_LEFT_BUTTON])
+ { // Left double click
+ return pControl->OnMouseDoubleClick(MOUSE_LEFT_BUTTON, point);
+ }
+ else if (g_Mouse.bHold[MOUSE_LEFT_BUTTON] && g_Mouse.HasMoved(true))
+ { // Mouse Drag
+ return pControl->OnMouseDrag(g_Mouse.GetLastMove(), point);
+ }
+ else if (g_Mouse.GetWheel())
+ { // Mouse wheel
+ return pControl->OnMouseWheel(g_Mouse.GetWheel(), point);
+ }
+ // no mouse stuff done other than movement
+ return false;
+}
+
+/// \brief Called on window open.
+/// * Restores the control state(s)
+/// * Sets initial visibility of controls
+/// * Queue WindowOpen animation
+/// * Set overlay state
+/// Override this function and do any window-specific initialisation such
+/// as filling control contents and setting control focus before
+/// calling the base method.
+void CGUIWindow::OnInitWindow()
+{
+ // set our rendered state
+ m_hasRendered = false;
+ ResetAnimations(); // we need to reset our animations as those windows that don't dynamically allocate
+ // need their anims reset. An alternative solution is turning off all non-dynamic
+ // allocation (which in some respects may be nicer, but it kills hdd spindown and the like)
+
+ // set our initial control visibility before restoring control state and
+ // focusing the default control, and again afterward to make sure that
+ // any controls that depend on the state of the focused control (and or on
+ // control states) are active.
+ SetInitialVisibility();
+ RestoreControlStates();
+ SetInitialVisibility();
+ QueueAnimation(ANIM_TYPE_WINDOW_OPEN);
+ m_gWindowManager.ShowOverlay(m_overlayState);
+
+ if (!m_manualRunActions)
+ {
+ RunLoadActions();
+ }
+}
+
+// Called on window close.
+// * Executes the window close animation(s)
+// * Saves control state(s)
+// Override this function and call the base class before doing any dynamic memory freeing
+void CGUIWindow::OnDeinitWindow(int nextWindowID)
+{
+ if (!m_manualRunActions)
+ {
+ RunUnloadActions();
+ }
+
+ if (nextWindowID != WINDOW_FULLSCREEN_VIDEO)
+ {
+ // Dialog animations are handled in Close() rather than here
+ if (HasAnimation(ANIM_TYPE_WINDOW_CLOSE) && !IsDialog() && IsActive())
+ {
+ // Perform the window out effect
+ QueueAnimation(ANIM_TYPE_WINDOW_CLOSE);
+ while (IsAnimating(ANIM_TYPE_WINDOW_CLOSE))
+ {
+ m_gWindowManager.Process(true);
+ }
+ }
+ }
+ SaveControlStates();
+}
+
+bool CGUIWindow::OnMessage(CGUIMessage& message)
+{
+ switch ( message.GetMessage() )
+ {
+ case GUI_MSG_WINDOW_INIT:
+ {
+ CLog::Log(LOGDEBUG, "------ Window Init (%s) ------", m_xmlFile.c_str());
+ if (m_dynamicResourceAlloc || !m_bAllocated) AllocResources();
+ OnInitWindow();
+ return true;
+ }
+ break;
+
+ case GUI_MSG_WINDOW_DEINIT:
+ {
+ CLog::Log(LOGDEBUG, "------ Window Deinit (%s) ------", m_xmlFile.c_str());
+ OnDeinitWindow(message.GetParam1());
+ // now free the window
+ if (m_dynamicResourceAlloc) FreeResources();
+ return true;
+ }
+ break;
+
+ case GUI_MSG_CLICKED:
+ {
+ // a specific control was clicked
+ CLICK_EVENT clickEvent = m_mapClickEvents[ message.GetSenderId() ];
+
+ // determine if there are any handlers for this event
+ if (clickEvent.HasAHandler())
+ {
+ // fire the message to all handlers
+ clickEvent.Fire(message);
+ }
+ break;
+ }
+
+ case GUI_MSG_SELCHANGED:
+ {
+ // a selection within a specific control has changed
+ SELECTED_EVENT selectedEvent = m_mapSelectedEvents[ message.GetSenderId() ];
+
+ // determine if there are any handlers for this event
+ if (selectedEvent.HasAHandler())
+ {
+ // fire the message to all handlers
+ selectedEvent.Fire(message);
+ }
+ break;
+ }
+ case GUI_MSG_FOCUSED:
+ { // a control has been focused
+ if (HasID(message.GetSenderId()))
+ {
+ m_focusedControl = message.GetControlId();
+ return true;
+ }
+ break;
+ }
+ case GUI_MSG_LOSTFOCUS:
+ {
+ // nothing to do at the window level when we lose focus
+ return true;
+ }
+ case GUI_MSG_MOVE:
+ {
+ if (HasID(message.GetSenderId()))
+ return OnMove(message.GetControlId(), message.GetParam1());
+ break;
+ }
+ case GUI_MSG_SETFOCUS:
+ {
+// CLog::Log(LOGDEBUG,"set focus to control:%i window:%i (%i)\n", message.GetControlId(),message.GetSenderId(), GetID());
+ if ( message.GetControlId() )
+ {
+ // first unfocus the current control
+ CGUIControl *control = GetFocusedControl();
+ if (control)
+ {
+ CGUIMessage msgLostFocus(GUI_MSG_LOSTFOCUS, GetID(), control->GetID(), message.GetControlId());
+ control->OnMessage(msgLostFocus);
+ }
+
+ // get the control to focus
+ CGUIControl* pFocusedControl = GetFirstFocusableControl(message.GetControlId());
+ if (!pFocusedControl) pFocusedControl = (CGUIControl *)GetControl(message.GetControlId());
+
+ // and focus it
+ if (pFocusedControl)
+ return pFocusedControl->OnMessage(message);
+ }
+ return true;
+ }
+ break;
+ case GUI_MSG_NOTIFY_ALL:
+ {
+ // only process those notifications that come from this window, or those intended for every window
+ if (HasID(message.GetSenderId()) || !message.GetSenderId())
+ {
+ if (message.GetParam1() == GUI_MSG_PAGE_CHANGE ||
+ message.GetParam1() == GUI_MSG_REFRESH_THUMBS ||
+ message.GetParam1() == GUI_MSG_REFRESH_LIST)
+ { // alter the message accordingly, and send to all controls
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ {
+ CGUIControl *control = *it;
+ CGUIMessage msg(message.GetParam1(), message.GetControlId(), control->GetID(), message.GetParam2());
+ control->OnMessage(msg);
+ }
+ }
+ if (message.GetParam1() == GUI_MSG_INVALIDATE)
+ {
+ SetInvalid();
+ return true;
+ }
+ }
+ }
+ break;
+ }
+
+ return SendControlMessage(message);
+}
+
+void CGUIWindow::AllocResources(bool forceLoad /*= FALSE */)
+{
+ CSingleLock lock(g_graphicsContext);
+
+ LARGE_INTEGER start;
+ QueryPerformanceCounter(&start);
+
+ // load skin xml file
+ bool bHasPath=false;
+ if (m_xmlFile.Find("\\") > -1 || m_xmlFile.Find("/") > -1 )
+ bHasPath = true;
+ if (m_xmlFile.size() && (forceLoad || m_loadOnDemand || !m_windowLoaded))
+ Load(m_xmlFile,bHasPath);
+
+ LARGE_INTEGER slend;
+ QueryPerformanceCounter(&slend);
+
+ // and now allocate resources
+ CGUIControlGroup::AllocResources();
+
+ LARGE_INTEGER end, freq;
+ QueryPerformanceCounter(&end);
+ QueryPerformanceFrequency(&freq);
+ CLog::Log(LOGDEBUG,"Alloc resources: %.2fms (%.2f ms skin load)", 1000.f * (end.QuadPart - start.QuadPart) / freq.QuadPart, 1000.f * (slend.QuadPart - start.QuadPart) / freq.QuadPart);
+
+ m_bAllocated = true;
+}
+
+void CGUIWindow::FreeResources(bool forceUnload /*= FALSE */)
+{
+ m_bAllocated = false;
+ CGUIControlGroup::FreeResources();
+ //g_TextureManager.Dump();
+ // unload the skin
+ if (m_loadOnDemand || forceUnload) ClearAll();
+}
+
+void CGUIWindow::DynamicResourceAlloc(bool bOnOff)
+{
+ m_dynamicResourceAlloc = bOnOff;
+ CGUIControlGroup::DynamicResourceAlloc(bOnOff);
+}
+
+void CGUIWindow::ClearAll()
+{
+ OnWindowUnload();
+ CGUIControlGroup::ClearAll();
+ m_windowLoaded = false;
+ m_dynamicResourceAlloc = true;
+}
+
+bool CGUIWindow::Initialize()
+{
+ return Load(m_xmlFile);
+}
+
+void CGUIWindow::SetInitialVisibility()
+{
+ // reset our info manager caches
+ g_infoManager.ResetCache();
+ CGUIControlGroup::SetInitialVisibility();
+}
+
+bool CGUIWindow::IsActive() const
+{
+ return m_gWindowManager.IsWindowActive(GetID());
+}
+
+bool CGUIWindow::CheckAnimation(ANIMATION_TYPE animType)
+{
+ // special cases first
+ if (animType == ANIM_TYPE_WINDOW_CLOSE)
+ {
+ if (!m_bAllocated || !m_hasRendered) // can't render an animation if we aren't allocated or haven't rendered
+ return false;
+ // make sure we update our visibility prior to queuing the window close anim
+ for (unsigned int i = 0; i < m_children.size(); i++)
+ m_children[i]->UpdateVisibility();
+ }
+ return true;
+}
+
+bool CGUIWindow::IsAnimating(ANIMATION_TYPE animType)
+{
+ if (!m_animationsEnabled)
+ return false;
+ return CGUIControlGroup::IsAnimating(animType);
+}
+
+bool CGUIWindow::RenderAnimation(DWORD time)
+{
+ g_graphicsContext.ResetWindowTransform();
+ if (m_animationsEnabled)
+ CGUIControlGroup::Animate(time);
+ else
+ m_transform.Reset();
+ return true;
+}
+
+void CGUIWindow::DisableAnimations()
+{
+ m_animationsEnabled = false;
+}
+
+// returns true if the control group with id groupID has controlID as
+// its focused control
+bool CGUIWindow::ControlGroupHasFocus(int groupID, int controlID)
+{
+ // 1. Run through and get control with groupID (assume unique)
+ // 2. Get it's selected item.
+ CGUIControl *group = GetFirstFocusableControl(groupID);
+ if (!group) group = (CGUIControl *)GetControl(groupID);
+
+ if (group && group->IsGroup())
+ {
+ if (controlID == 0)
+ { // just want to know if the group is focused
+ return group->HasFocus();
+ }
+ else
+ {
+ CGUIMessage message(GUI_MSG_ITEM_SELECTED, GetID(), group->GetID());
+ group->OnMessage(message);
+ return (controlID == (int) message.GetParam1());
+ }
+ }
+ return false;
+}
+
+void CGUIWindow::SaveControlStates()
+{
+ ResetControlStates();
+ if (!m_defaultAlways)
+ m_lastControlID = GetFocusedControlID();
+ for (iControls it = m_children.begin(); it != m_children.end(); ++it)
+ (*it)->SaveStates(m_controlStates);
+}
+
+void CGUIWindow::RestoreControlStates()
+{
+ for (vector<CControlState>::iterator it = m_controlStates.begin(); it != m_controlStates.end(); ++it)
+ {
+ CGUIMessage message(GUI_MSG_ITEM_SELECT, GetID(), (*it).m_id, (*it).m_data);
+ OnMessage(message);
+ }
+ int focusControl = (!m_defaultAlways && m_lastControlID) ? m_lastControlID : m_defaultControl;
+ SET_CONTROL_FOCUS(focusControl, 0);
+}
+
+void CGUIWindow::ResetControlStates()
+{
+ m_lastControlID = 0;
+ m_focusedControl = 0;
+ m_controlStates.clear();
+}
+
+bool CGUIWindow::OnMove(int fromControl, int moveAction)
+{
+ const CGUIControl *control = GetFirstFocusableControl(fromControl);
+ if (!control) control = GetControl(fromControl);
+ if (!control)
+ { // no current control??
+ CLog::Log(LOGERROR, "Unable to find control %i in window %u",
+ fromControl, GetID());
+ return false;
+ }
+ vector<int> moveHistory;
+ int nextControl = fromControl;
+ while (control)
+ { // grab the next control direction
+ moveHistory.push_back(nextControl);
+ nextControl = control->GetNextControl(moveAction);
+ // check our history - if the nextControl is in it, we can't focus it
+ for (unsigned int i = 0; i < moveHistory.size(); i++)
+ {
+ if (nextControl == moveHistory[i])
+ return false; // no control to focus so do nothing
+ }
+ control = GetFirstFocusableControl(nextControl);
+ if (control)
+ break; // found a focusable control
+ control = GetControl(nextControl); // grab the next control and try again
+ }
+ if (!control)
+ return false; // no control to focus
+ // if we get here we have our new control so focus it (and unfocus the current control)
+ SET_CONTROL_FOCUS(nextControl, 0);
+ return true;
+}
+
+void CGUIWindow::SetDefaults()
+{
+ m_renderOrder = 0;
+ m_defaultAlways = false;
+ m_defaultControl = 0;
+ m_bRelativeCoords = false;
+ m_posX = m_posY = m_width = m_height = 0;
+ m_overlayState = OVERLAY_STATE_PARENT_WINDOW; // Use parent or previous window's state
+ m_visibleCondition = 0;
+ m_previousWindow = WINDOW_INVALID;
+ m_animations.clear();
+ m_origins.clear();
+ m_hasCamera = false;
+ m_animationsEnabled = true;
+}
+
+FRECT CGUIWindow::GetScaledBounds() const
+{
+ CSingleLock lock(g_graphicsContext);
+ g_graphicsContext.SetScalingResolution(m_coordsRes, m_posX, m_posY, m_needsScaling);
+ FRECT rect = {0, 0, m_width, m_height};
+ float z = 0;
+ g_graphicsContext.ScaleFinalCoords(rect.left, rect.top, z);
+ g_graphicsContext.ScaleFinalCoords(rect.right, rect.bottom, z);
+ return rect;
+}
+
+void CGUIWindow::OnEditChanged(int id, CStdString &text)
+{
+ CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), id);
+ OnMessage(msg);
+ text = msg.GetLabel();
+}
+
+bool CGUIWindow::SendMessage(int message, int id, int param1 /* = 0*/, int param2 /* = 0*/)
+{
+ CGUIMessage msg(message, GetID(), id, param1, param2);
+ return OnMessage(msg);
+}
+
+#ifdef _DEBUG
+void CGUIWindow::DumpTextureUse()
+{
+ CLog::Log(LOGDEBUG, "%s for window %u", __FUNCTION__, GetID());
+ CGUIControlGroup::DumpTextureUse();
+}
+#endif
+
+void CGUIWindow::ChangeButtonToEdit(int id, bool singleLabel /* = false*/)
+{
+#ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY
+ CGUIControl *name = (CGUIControl *)GetControl(id);
+ if (name && name->GetControlType() == CGUIControl::GUICONTROL_BUTTON)
+ { // change it to an edit control
+ CGUIEditControl *edit = new CGUIEditControl(*(const CGUIButtonControl *)name);
+ if (edit)
+ {
+ if (singleLabel)
+ edit->SetLabel("");
+ InsertControl(edit, name);
+ RemoveControl(name);
+ name->FreeResources();
+ delete name;
+ }
+ }
+#endif
+}
+
+void CGUIWindow::SetProperty(const CStdString &strKey, const char *strValue)
+{
+ m_mapProperties[strKey] = strValue;
+}
+
+void CGUIWindow::SetProperty(const CStdString &strKey, const CStdString &strValue)
+{
+ m_mapProperties[strKey] = strValue;
+}
+
+void CGUIWindow::SetProperty(const CStdString &strKey, int nVal)
+{
+ CStdString strVal;
+ strVal.Format("%d",nVal);
+ SetProperty(strKey, strVal);
+}
+
+void CGUIWindow::SetProperty(const CStdString &strKey, bool bVal)
+{
+ SetProperty(strKey, bVal?"1":"0");
+}
+
+void CGUIWindow::SetProperty(const CStdString &strKey, double dVal)
+{
+ CStdString strVal;
+ strVal.Format("%f",dVal);
+ SetProperty(strKey, strVal);
+}
+
+CStdString CGUIWindow::GetProperty(const CStdString &strKey) const
+{
+ std::map<CStdString,CStdString,icompare>::const_iterator iter = m_mapProperties.find(strKey);
+ if (iter == m_mapProperties.end())
+ return "";
+
+ return iter->second;
+}
+
+int CGUIWindow::GetPropertyInt(const CStdString &strKey) const
+{
+ return atoi(GetProperty(strKey).c_str()) ;
+}
+
+bool CGUIWindow::GetPropertyBOOL(const CStdString &strKey) const
+{
+ return GetProperty(strKey) == "1";
+}
+
+double CGUIWindow::GetPropertyDouble(const CStdString &strKey) const
+{
+ return atof(GetProperty(strKey).c_str()) ;
+}
+
+bool CGUIWindow::HasProperty(const CStdString &strKey) const
+{
+ std::map<CStdString,CStdString,icompare>::const_iterator iter = m_mapProperties.find(strKey);
+ if (iter == m_mapProperties.end())
+ return FALSE;
+
+ return TRUE;
+ }
+
+void CGUIWindow::ClearProperty(const CStdString &strKey)
+{
+ std::map<CStdString,CStdString,icompare>::iterator iter = m_mapProperties.find(strKey);
+ if (iter != m_mapProperties.end())
+ m_mapProperties.erase(iter);
+}
+
+void CGUIWindow::ClearProperties()
+{
+ m_mapProperties.clear();
+}
+
+void CGUIWindow::RunActions(std::vector<CGUIActionDescriptor>& actions)
+{
+ vector<CGUIActionDescriptor> tempActions = actions;
+
+ // and execute our actions
+ for (unsigned int i = 0; i < tempActions.size(); i++)
+ {
+ CGUIMessage message(GUI_MSG_EXECUTE, 0, GetID());
+ message.SetAction(tempActions[i]);
+ g_graphicsContext.SendMessage(message);
+ }
+}
+
+void CGUIWindow::SetRunActionsManually()
+{
+ m_manualRunActions = true;
+}
+
+void CGUIWindow::RunLoadActions()
+{
+ RunActions(m_loadActions);
+}
+
+void CGUIWindow::RunUnloadActions()
+{
+ RunActions(m_unloadActions);
+}
diff --git a/guilib/GUIWindow.h b/guilib/GUIWindow.h
new file mode 100644
index 0000000000..868be691ff
--- /dev/null
+++ b/guilib/GUIWindow.h
@@ -0,0 +1,243 @@
+/*!
+\file GUIWindow.h
+\brief
+*/
+
+#ifndef GUILIB_GUIWINDOW_H
+#define GUILIB_GUIWINDOW_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIControlGroup.h"
+#include "boost/shared_ptr.hpp"
+
+class CFileItem; typedef boost::shared_ptr<CFileItem> CFileItemPtr;
+
+#include "GUICallback.h" // for GUIEvent
+
+#include <map>
+#include <vector>
+
+#define ON_CLICK_MESSAGE(i,c,m) \
+{ \
+ GUIEventHandler<c, CGUIMessage&> clickHandler(this, &m); \
+ m_mapClickEvents[i] = clickHandler; \
+} \
+
+#define ON_SELECTED_MESSAGE(i,c,m) \
+{ \
+ GUIEventHandler<c, CGUIMessage&> selectedHandler(this, &m); \
+ m_mapSelectedEvents[i] = selectedHandler; \
+} \
+
+// forward
+class TiXmlNode;
+class TiXmlElement;
+class TiXmlDocument;
+
+class COrigin
+{
+public:
+ COrigin()
+ {
+ x = y = 0;
+ condition = 0;
+ };
+ float x;
+ float y;
+ int condition;
+};
+
+/*!
+ \ingroup winmsg
+ \brief
+ */
+class CGUIWindow : public CGUIControlGroup
+{
+public:
+ enum WINDOW_TYPE { WINDOW = 0, MODAL_DIALOG, MODELESS_DIALOG, BUTTON_MENU, SUB_MENU };
+
+ CGUIWindow(int id, const CStdString &xmlFile);
+ virtual ~CGUIWindow(void);
+
+ bool Initialize(); // loads the window
+ bool Load(const CStdString& strFileName, bool bContainsPath = false);
+
+ void CenterWindow();
+ virtual void Render();
+
+ // Close should never be called on this base class (only on derivatives) - its here so that window-manager can use a general close
+ virtual void Close(bool forceClose = false);
+
+ // OnAction() is called by our window manager. We should process any messages
+ // that should be handled at the window level in the derived classes, and any
+ // unhandled messages should be dropped through to here where we send the message
+ // on to the currently focused control. Returns true if the action has been handled
+ // and does not need to be passed further down the line (to our global action handlers)
+ virtual bool OnAction(const CAction &action);
+
+ virtual bool OnMouse(const CPoint &point);
+ bool HandleMouse(CGUIControl *pControl, const CPoint &point);
+ bool OnMove(int fromControl, int moveAction);
+ virtual bool OnMessage(CGUIMessage& message);
+
+ bool ControlGroupHasFocus(int groupID, int controlID);
+ virtual bool HasID(int id) { return (id >= m_controlID && id < m_controlID + m_idRange); };
+ void SetIDRange(int range) { m_idRange = range; };
+ int GetIDRange() const { return m_idRange; };
+ int GetPreviousWindow() { return m_previousWindow; };
+ FRECT GetScaledBounds() const;
+ virtual void ClearAll();
+ virtual void AllocResources(bool forceLoad = false);
+ virtual void FreeResources(bool forceUnLoad = false);
+ virtual void DynamicResourceAlloc(bool bOnOff);
+ virtual bool IsDialog() const { return false; };
+ virtual bool IsDialogRunning() const { return false; };
+ virtual bool IsModalDialog() const { return false; };
+ virtual bool IsMediaWindow() const { return false; };
+ virtual bool HasListItems() const { return false; };
+ virtual CFileItemPtr GetCurrentListItem(int offset = 0) { return CFileItemPtr(); };
+ virtual int GetViewContainerID() const { return 0; };
+ virtual bool IsActive() const;
+ void SetCoordsRes(RESOLUTION res) { m_coordsRes = res; };
+ RESOLUTION GetCoordsRes() const { return m_coordsRes; };
+ void SetXMLFile(const CStdString &xmlFile) { m_xmlFile = xmlFile; };
+ const CStdString &GetXMLFile() const { return m_xmlFile; };
+ void LoadOnDemand(bool loadOnDemand) { m_loadOnDemand = loadOnDemand; };
+ bool GetLoadOnDemand() { return m_loadOnDemand; }
+ int GetRenderOrder() { return m_renderOrder; };
+ virtual void SetInitialVisibility();
+
+ enum OVERLAY_STATE { OVERLAY_STATE_PARENT_WINDOW=0, OVERLAY_STATE_SHOWN, OVERLAY_STATE_HIDDEN };
+
+ OVERLAY_STATE GetOverlayState() const { return m_overlayState; };
+
+ virtual bool IsAnimating(ANIMATION_TYPE animType);
+ void DisableAnimations();
+
+ virtual void ResetControlStates();
+
+ void SetRunActionsManually();
+ void RunLoadActions();
+ void RunUnloadActions();
+
+ bool HasProperty(const CStdString &strKey) const;
+ void SetProperty(const CStdString &strKey, const char *strValue);
+ void SetProperty(const CStdString &strKey, const CStdString &strValue);
+ void SetProperty(const CStdString &strKey, int nVal);
+ void SetProperty(const CStdString &strKey, bool bVal);
+ void SetProperty(const CStdString &strKey, double dVal);
+
+ CStdString GetProperty(const CStdString &strKey) const;
+ int GetPropertyInt(const CStdString &strKey) const;
+ bool GetPropertyBOOL(const CStdString &strKey) const;
+ double GetPropertyDouble(const CStdString &strKey) const;
+
+ void ClearProperties();
+ void ClearProperty(const CStdString &strKey);
+
+#ifdef _DEBUG
+ void DumpTextureUse();
+#endif
+
+ bool HasSaveLastControl() const { return !m_defaultAlways; };
+
+protected:
+ virtual bool LoadXML(const CStdString& strPath, const CStdString &strLowerPath); ///< Loads from the given file
+ bool Load(TiXmlDocument &xmlDoc); ///< Loads from the given XML document
+ virtual void LoadAdditionalTags(TiXmlElement *root) {}; ///< Load additional information from the XML document
+
+ virtual void SetDefaults();
+ virtual void OnWindowUnload() {}
+ virtual void OnWindowLoaded();
+ virtual void OnInitWindow();
+ virtual void OnDeinitWindow(int nextWindowID);
+ virtual bool OnMouseAction();
+ virtual bool RenderAnimation(DWORD time);
+ virtual bool CheckAnimation(ANIMATION_TYPE animType);
+
+ CAnimation *GetAnimation(ANIMATION_TYPE animType, bool checkConditions = true);
+
+ // control state saving on window close
+ virtual void SaveControlStates();
+ virtual void RestoreControlStates();
+
+ // methods for updating controls and sending messages
+ void OnEditChanged(int id, CStdString &text);
+ bool SendMessage(int message, int id, int param1 = 0, int param2 = 0);
+
+ typedef GUIEvent<CGUIMessage&> CLICK_EVENT;
+ typedef std::map<int, CLICK_EVENT> MAPCONTROLCLICKEVENTS;
+ MAPCONTROLCLICKEVENTS m_mapClickEvents;
+
+ typedef GUIEvent<CGUIMessage&> SELECTED_EVENT;
+ typedef std::map<int, SELECTED_EVENT> MAPCONTROLSELECTEDEVENTS;
+ MAPCONTROLSELECTEDEVENTS m_mapSelectedEvents;
+
+ void LoadControl(TiXmlElement* pControl, CGUIControlGroup *pGroup);
+
+//#ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY
+ void ChangeButtonToEdit(int id, bool singleLabel = false);
+//#endif
+
+ void RunActions(std::vector<CGUIActionDescriptor>& actions);
+
+ int m_idRange;
+ bool m_bRelativeCoords;
+ OVERLAY_STATE m_overlayState;
+ RESOLUTION m_coordsRes; // resolution that the window coordinates are in.
+ bool m_needsScaling;
+ CStdString m_xmlFile; // xml file to load
+ bool m_windowLoaded; // true if the window's xml file has been loaded
+ bool m_loadOnDemand; // true if the window should be loaded only as needed
+ bool m_isDialog; // true if we have a dialog, false otherwise.
+ bool m_dynamicResourceAlloc;
+
+ int m_renderOrder; // for render order of dialogs
+
+ std::vector<COrigin> m_origins; // positions of dialogs depending on base window
+
+ // control states
+ int m_lastControlID;
+ std::vector<CControlState> m_controlStates;
+ int m_previousWindow;
+
+ bool m_animationsEnabled;
+ struct icompare
+ {
+ bool operator()(const CStdString &s1, const CStdString &s2) const
+ {
+ return s1.CompareNoCase(s2) < 0;
+ }
+ };
+
+ std::map<CStdString, CStdString, icompare> m_mapProperties;
+
+ std::vector<CGUIActionDescriptor> m_loadActions;
+ std::vector<CGUIActionDescriptor> m_unloadActions;
+
+ bool m_manualRunActions;
+};
+
+#endif
diff --git a/guilib/GUIWindowManager.cpp b/guilib/GUIWindowManager.cpp
new file mode 100644
index 0000000000..e2ec0761d8
--- /dev/null
+++ b/guilib/GUIWindowManager.cpp
@@ -0,0 +1,891 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIWindowManager.h"
+#include "GUIAudioManager.h"
+#include "GUIDialog.h"
+#include "Application.h"
+#include "GUIPassword.h"
+#include "utils/GUIInfoManager.h"
+#include "Util.h"
+#include "GUISettings.h"
+#include "Settings.h"
+
+using namespace std;
+
+CGUIWindowManager m_gWindowManager;
+
+CGUIWindowManager::CGUIWindowManager(void)
+{
+ InitializeCriticalSection(&m_critSection);
+
+ m_pCallback = NULL;
+ m_bShowOverlay = true;
+}
+
+CGUIWindowManager::~CGUIWindowManager(void)
+{
+ DeleteCriticalSection(&m_critSection);
+}
+
+void CGUIWindowManager::Initialize()
+{
+ g_graphicsContext.setMessageSender(this);
+ LoadNotOnDemandWindows();
+}
+
+bool CGUIWindowManager::SendMessage(CGUIMessage& message)
+{
+ bool handled = false;
+// CLog::Log(LOGDEBUG,"SendMessage: mess=%d send=%d control=%d param1=%d", message.GetMessage(), message.GetSenderId(), message.GetControlId(), message.GetParam1());
+ // Send the message to all none window targets
+ for (int i = 0; i < (int) m_vecMsgTargets.size(); i++)
+ {
+ IMsgTargetCallback* pMsgTarget = m_vecMsgTargets[i];
+
+ if (pMsgTarget)
+ {
+ if (pMsgTarget->OnMessage( message )) handled = true;
+ }
+ }
+
+ // A GUI_MSG_NOTIFY_ALL is send to any active modal dialog
+ // and all windows whether they are active or not
+ if (message.GetMessage()==GUI_MSG_NOTIFY_ALL)
+ {
+ for (rDialog it = m_activeDialogs.rbegin(); it != m_activeDialogs.rend(); ++it)
+ {
+ CGUIWindow *dialog = *it;
+ dialog->OnMessage(message);
+ }
+
+ for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); it++)
+ {
+ CGUIWindow *pWindow = (*it).second;
+ pWindow->OnMessage(message);
+ }
+ return true;
+ }
+
+ // Normal messages are sent to:
+ // 1. All active modeless dialogs
+ // 2. The topmost dialog that accepts the message
+ // 3. The underlying window (only if it is the sender or receiver if a modal dialog is active)
+
+ bool hasModalDialog(false);
+ bool modalAcceptedMessage(false);
+ // don't use an iterator for this loop, as some messages mean that m_activeDialogs is altered,
+ // which will invalidate any iterator
+ unsigned int topWindow = m_activeDialogs.size();
+ while (topWindow)
+ {
+ CGUIWindow* dialog = m_activeDialogs[--topWindow];
+ if (!modalAcceptedMessage && dialog->IsModalDialog())
+ { // modal window
+ hasModalDialog = true;
+ if (!modalAcceptedMessage && dialog->OnMessage( message ))
+ {
+ modalAcceptedMessage = handled = true;
+ }
+ }
+ else if (!dialog->IsModalDialog())
+ { // modeless
+ if (dialog->OnMessage( message ))
+ handled = true;
+ }
+ }
+
+ // now send to the underlying window
+ CGUIWindow* window = GetWindow(GetActiveWindow());
+ if (window)
+ {
+ if (hasModalDialog)
+ {
+ // only send the message to the underlying window if it's the recipient
+ // or sender (or we have no sender)
+ if (message.GetSenderId() == window->GetID() ||
+ message.GetControlId() == window->GetID() ||
+ message.GetSenderId() == 0 )
+ {
+ if (window->OnMessage(message)) handled = true;
+ }
+ }
+ else
+ {
+ if (window->OnMessage(message)) handled = true;
+ }
+ }
+ return handled;
+}
+
+bool CGUIWindowManager::SendMessage(CGUIMessage& message, int window)
+{
+ CGUIWindow* pWindow = GetWindow(window);
+ if(pWindow)
+ return pWindow->OnMessage(message);
+ else
+ return false;
+}
+
+void CGUIWindowManager::AddUniqueInstance(CGUIWindow *window)
+{
+ // increment our instance (upper word of windowID)
+ // until we get a window we don't have
+ int instance = 0;
+ while (GetWindow(window->GetID()))
+ window->SetID(window->GetID() + (++instance << 16));
+ Add(window);
+}
+
+void CGUIWindowManager::Add(CGUIWindow* pWindow)
+{
+ if (!pWindow)
+ {
+ CLog::Log(LOGERROR, "Attempted to add a NULL window pointer to the window manager.");
+ return;
+ }
+ // push back all the windows if there are more than one covered by this class
+ for (int i = 0; i < pWindow->GetIDRange(); i++)
+ {
+ WindowMap::iterator it = m_mapWindows.find(pWindow->GetID() + i);
+ if (it != m_mapWindows.end())
+ {
+ CLog::Log(LOGERROR, "Error, trying to add a second window with id %u "
+ "to the window manager",
+ pWindow->GetID());
+ return;
+ }
+ m_mapWindows.insert(pair<int, CGUIWindow *>(pWindow->GetID() + i, pWindow));
+ }
+}
+
+void CGUIWindowManager::AddCustomWindow(CGUIWindow* pWindow)
+{
+ Add(pWindow);
+ m_vecCustomWindows.push_back(pWindow);
+}
+
+void CGUIWindowManager::AddModeless(CGUIWindow* dialog)
+{
+ // only add the window if it's not already added
+ for (iDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
+ if (*it == dialog) return;
+ m_activeDialogs.push_back(dialog);
+}
+
+void CGUIWindowManager::Remove(int id)
+{
+ WindowMap::iterator it = m_mapWindows.find(id);
+ if (it != m_mapWindows.end())
+ {
+ m_mapWindows.erase(it);
+ }
+ else
+ {
+ CLog::Log(LOGWARNING, "Attempted to remove window %u "
+ "from the window manager when it didn't exist",
+ id);
+ }
+}
+
+// removes and deletes the window. Should only be called
+// from the class that created the window using new.
+void CGUIWindowManager::Delete(int id)
+{
+ CGUIWindow *pWindow = GetWindow(id);
+ if (pWindow)
+ {
+ Remove(id);
+ delete pWindow;
+ }
+}
+
+void CGUIWindowManager::PreviousWindow()
+{
+ // deactivate any window
+ CLog::Log(LOGDEBUG,"CGUIWindowManager::PreviousWindow: Deactivate");
+ int currentWindow = GetActiveWindow();
+ CGUIWindow *pCurrentWindow = GetWindow(currentWindow);
+ if (!pCurrentWindow)
+ return; // no windows or window history yet
+
+ // check to see whether our current window has a <previouswindow> tag
+ if (pCurrentWindow->GetPreviousWindow() != WINDOW_INVALID)
+ {
+ // TODO: we may need to test here for the
+ // whether our history should be changed
+
+ // don't reactivate the previouswindow if it is ourselves.
+ if (currentWindow != pCurrentWindow->GetPreviousWindow())
+ ActivateWindow(pCurrentWindow->GetPreviousWindow());
+ return;
+ }
+ // get the previous window in our stack
+ if (m_windowHistory.size() < 2)
+ { // no previous window history yet - check if we should just activate home
+ if (GetActiveWindow() != WINDOW_INVALID && GetActiveWindow() != WINDOW_HOME)
+ {
+ ClearWindowHistory();
+ ActivateWindow(WINDOW_HOME);
+ }
+ return;
+ }
+ m_windowHistory.pop();
+ int previousWindow = GetActiveWindow();
+ m_windowHistory.push(currentWindow);
+
+ CGUIWindow *pNewWindow = GetWindow(previousWindow);
+ if (!pNewWindow)
+ {
+ CLog::Log(LOGERROR, "Unable to activate the previous window");
+ ClearWindowHistory();
+ ActivateWindow(WINDOW_HOME);
+ return;
+ }
+
+ // ok to go to the previous window now
+
+ // tell our info manager which window we are going to
+ g_infoManager.SetNextWindow(previousWindow);
+
+ // set our overlay state (enables out animations on window change)
+ HideOverlay(pNewWindow->GetOverlayState());
+
+ // deinitialize our window
+ g_audioManager.PlayWindowSound(pCurrentWindow->GetID(), SOUND_DEINIT);
+ CGUIMessage msg(GUI_MSG_WINDOW_DEINIT, 0, 0);
+ pCurrentWindow->OnMessage(msg);
+
+ g_infoManager.SetNextWindow(WINDOW_INVALID);
+ g_infoManager.SetPreviousWindow(currentWindow);
+
+ // remove the current window off our window stack
+ m_windowHistory.pop();
+
+ // ok, initialize the new window
+ CLog::Log(LOGDEBUG,"CGUIWindowManager::PreviousWindow: Activate new");
+ g_audioManager.PlayWindowSound(pNewWindow->GetID(), SOUND_INIT);
+ CGUIMessage msg2(GUI_MSG_WINDOW_INIT, 0, 0, WINDOW_INVALID, GetActiveWindow());
+ pNewWindow->OnMessage(msg2);
+
+ g_infoManager.SetPreviousWindow(WINDOW_INVALID);
+ return;
+}
+
+void CGUIWindowManager::RefreshWindow()
+{
+ // deactivate the current window
+ CGUIWindow *pWindow = GetWindow(GetActiveWindow());
+ if (!pWindow)
+ return;
+
+ CGUIMessage msg(GUI_MSG_WINDOW_DEINIT, 0, 0);
+ pWindow->OnMessage(msg);
+ CGUIMessage msg2(GUI_MSG_WINDOW_INIT, 0, 0, WINDOW_INVALID);
+ pWindow->OnMessage(msg2);
+}
+
+void CGUIWindowManager::ChangeActiveWindow(int newWindow, const CStdString& strPath)
+{
+ vector<CStdString> params;
+ if (!strPath.IsEmpty())
+ params.push_back(strPath);
+ ActivateWindow(newWindow, params, true);
+}
+
+void CGUIWindowManager::ActivateWindow(int iWindowID, const CStdString& strPath)
+{
+ vector<CStdString> params;
+ if (!strPath.IsEmpty())
+ params.push_back(strPath);
+ ActivateWindow(iWindowID, params, false);
+}
+
+void CGUIWindowManager::ActivateWindow(int iWindowID, const vector<CStdString>& params, bool swappingWindows)
+{
+ if (!g_application.IsCurrentThread())
+ {
+ // make sure graphics lock is not held
+ int nCount = ExitCriticalSection(g_graphicsContext);
+ g_application.getApplicationMessenger().ActivateWindow(iWindowID, params, swappingWindows);
+ RestoreCriticalSection(g_graphicsContext, nCount);
+ }
+ else
+ ActivateWindow_Internal(iWindowID, params, swappingWindows);
+}
+
+void CGUIWindowManager::ActivateWindow_Internal(int iWindowID, const vector<CStdString>& params, bool swappingWindows)
+{
+ bool passParams = true;
+ // translate virtual windows
+ // virtual music window which returns the last open music window (aka the music start window)
+ if (iWindowID == WINDOW_MUSIC)
+ {
+ iWindowID = g_stSettings.m_iMyMusicStartWindow;
+ // ensure the music virtual window only returns music files and music library windows
+ if (iWindowID != WINDOW_MUSIC_NAV)
+ iWindowID = WINDOW_MUSIC_FILES;
+ // destination path cannot be used with virtual window
+ passParams = false;
+ }
+ // virtual video window which returns the last open video window (aka the video start window)
+ if (iWindowID == WINDOW_VIDEOS)
+ {
+ iWindowID = g_stSettings.m_iVideoStartWindow;
+ // ensure the virtual video window only returns video windows
+ if (iWindowID != WINDOW_VIDEO_NAV)
+ iWindowID = WINDOW_VIDEO_FILES;
+ // destination path cannot be used with virtual window
+ passParams = false;
+ }
+ // Is the Library enabled? If not, go to Files view.
+ if (iWindowID == WINDOW_MUSIC_NAV && !g_guiSettings.GetBool("musiclibrary.enabled"))
+ {
+ iWindowID = WINDOW_MUSIC_FILES;
+ passParams = false;
+ CLog::Log(LOGDEBUG, "Trying to activate Music Library, but its disabled. Switching to Files instead.");
+ }
+ if (iWindowID == WINDOW_VIDEO_NAV && !g_guiSettings.GetBool("videolibrary.enabled"))
+ {
+ iWindowID = WINDOW_VIDEO_FILES;
+ passParams = false;
+ CLog::Log(LOGDEBUG, "Trying to activate Video Library, but its disabled. Switching to Files instead.");
+ }
+
+ // debug
+ CLog::Log(LOGDEBUG, "Activating window ID: %i", iWindowID);
+
+ if(!g_passwordManager.CheckMenuLock(iWindowID))
+ {
+ CLog::Log(LOGERROR, "MasterCode is Wrong: Window with id %d will not be loaded! Enter a correct MasterCode!", iWindowID);
+ return;
+ }
+
+ // first check existence of the window we wish to activate.
+ CGUIWindow *pNewWindow = GetWindow(iWindowID);
+ if (!pNewWindow)
+ { // nothing to see here - move along
+ CLog::Log(LOGERROR, "Unable to locate window with id %d. Check skin files", iWindowID - WINDOW_HOME);
+ return ;
+ }
+ else if (pNewWindow->IsDialog())
+ { // if we have a dialog, we do a DoModal() rather than activate the window
+ if (!pNewWindow->IsDialogRunning())
+ ((CGUIDialog *)pNewWindow)->DoModal(iWindowID, (passParams && params.size()) ? params[0] : "");
+ return;
+ }
+
+ g_infoManager.SetNextWindow(iWindowID);
+
+ // set our overlay state
+ HideOverlay(pNewWindow->GetOverlayState());
+
+ // deactivate any window
+ int currentWindow = GetActiveWindow();
+ CGUIWindow *pWindow = GetWindow(currentWindow);
+ if (pWindow)
+ {
+ // Play the window specific deinit sound
+ g_audioManager.PlayWindowSound(pWindow->GetID(), SOUND_DEINIT);
+ CGUIMessage msg(GUI_MSG_WINDOW_DEINIT, 0, 0, iWindowID);
+ pWindow->OnMessage(msg);
+ }
+ g_infoManager.SetNextWindow(WINDOW_INVALID);
+
+ // Add window to the history list (we must do this before we activate it,
+ // as all messages done in WINDOW_INIT will want to be sent to the new
+ // topmost window). If we are swapping windows, we pop the old window
+ // off the history stack
+ if (swappingWindows && m_windowHistory.size())
+ m_windowHistory.pop();
+ AddToWindowHistory(iWindowID);
+
+ g_infoManager.SetPreviousWindow(currentWindow);
+ g_audioManager.PlayWindowSound(pNewWindow->GetID(), SOUND_INIT);
+ // Send the init message
+ CGUIMessage msg(GUI_MSG_WINDOW_INIT, 0, 0, currentWindow, iWindowID);
+ if (passParams)
+ msg.SetStringParams(params);
+ pNewWindow->OnMessage(msg);
+// g_infoManager.SetPreviousWindow(WINDOW_INVALID);
+}
+
+void CGUIWindowManager::CloseDialogs(bool forceClose)
+{
+ while (m_activeDialogs.size() > 0)
+ {
+ CGUIWindow* win = m_activeDialogs[0];
+ win->Close(forceClose);
+ }
+}
+
+bool CGUIWindowManager::OnAction(const CAction &action)
+{
+ for (rDialog it = m_activeDialogs.rbegin(); it != m_activeDialogs.rend(); ++it)
+ {
+ CGUIWindow *dialog = *it;
+ if (dialog->IsModalDialog())
+ { // we have the topmost modal dialog
+ if (!dialog->IsAnimating(ANIM_TYPE_WINDOW_CLOSE))
+ {
+ if (dialog->OnAction(action))
+ return true;
+ // dialog didn't want the action - we'd normally return true
+ // but for some dialogs we want to drop the actions through
+ if (dialog->GetID() == WINDOW_DIALOG_FULLSCREEN_INFO)
+ break;
+ return false;
+ }
+ return true; // do nothing with the action until the anim is finished
+ }
+ // music or video overlay are handled as a special case, as they're modeless, but we allow
+ // clicking on them with the mouse.
+ if (action.id == ACTION_MOUSE && (dialog->GetID() == WINDOW_VIDEO_OVERLAY ||
+ dialog->GetID() == WINDOW_MUSIC_OVERLAY))
+ {
+ if (dialog->OnAction(action))
+ return true;
+ }
+ }
+ CGUIWindow* window = GetWindow(GetActiveWindow());
+ if (window)
+ return window->OnAction(action);
+ return false;
+}
+
+void CGUIWindowManager::Render()
+{
+ if (!g_application.IsCurrentThread())
+ {
+ // make sure graphics lock is not held
+ int nCount = ExitCriticalSection(g_graphicsContext);
+ g_application.getApplicationMessenger().Render();
+ RestoreCriticalSection(g_graphicsContext, nCount);
+ }
+ else
+ Render_Internal();
+}
+
+void CGUIWindowManager::Render_Internal()
+{
+ CGUIWindow* pWindow = GetWindow(GetActiveWindow());
+ if (pWindow)
+ pWindow->Render();
+}
+
+bool RenderOrderSortFunction(CGUIWindow *first, CGUIWindow *second)
+{
+ return first->GetRenderOrder() < second->GetRenderOrder();
+}
+
+void CGUIWindowManager::RenderDialogs()
+{
+ // find the window with the lowest render order
+ vector<CGUIWindow *> renderList = m_activeDialogs;
+ stable_sort(renderList.begin(), renderList.end(), RenderOrderSortFunction);
+
+ // iterate through and render if they're running
+ for (iDialog it = renderList.begin(); it != renderList.end(); ++it)
+ {
+ if ((*it)->IsDialogRunning())
+ (*it)->Render();
+ }
+}
+
+CGUIWindow* CGUIWindowManager::GetWindow(int id) const
+{
+ if (id == WINDOW_INVALID)
+ {
+ return NULL;
+ }
+
+ WindowMap::const_iterator it = m_mapWindows.find(id);
+ if (it != m_mapWindows.end())
+ return (*it).second;
+ return NULL;
+}
+
+// Shows and hides modeless dialogs as necessary.
+void CGUIWindowManager::UpdateModelessVisibility()
+{
+ for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); it++)
+ {
+ CGUIWindow *pWindow = (*it).second;
+ if (pWindow && pWindow->IsDialog() && pWindow->GetVisibleCondition())
+ {
+ if (g_infoManager.GetBool(pWindow->GetVisibleCondition(), GetActiveWindow()))
+ ((CGUIDialog *)pWindow)->Show();
+ else
+ ((CGUIDialog *)pWindow)->Close();
+ }
+ }
+}
+
+void CGUIWindowManager::Process(bool renderOnly /*= false*/)
+{
+ if (!g_application.IsCurrentThread())
+ {
+ // make sure graphics lock is not held
+ DWORD locks = ExitCriticalSection(g_graphicsContext);
+ g_application.getApplicationMessenger().WindowManagerProcess(renderOnly);
+ RestoreCriticalSection(g_graphicsContext, locks);
+ }
+ else
+ Process_Internal(renderOnly);
+}
+
+void CGUIWindowManager::Process_Internal(bool renderOnly /*= false*/)
+{
+ if (m_pCallback)
+ {
+ if (!renderOnly)
+ {
+ m_pCallback->Process();
+ m_pCallback->FrameMove();
+ }
+ m_pCallback->Render();
+ }
+}
+
+void CGUIWindowManager::SetCallback(IWindowManagerCallback& callback)
+{
+ m_pCallback = &callback;
+}
+
+void CGUIWindowManager::DeInitialize()
+{
+ for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); it++)
+ {
+ CGUIWindow* pWindow = (*it).second;
+ if (IsWindowActive(it->first))
+ {
+ pWindow->DisableAnimations();
+ CGUIMessage msg(GUI_MSG_WINDOW_DEINIT, 0, 0);
+ pWindow->OnMessage(msg);
+ }
+ pWindow->ResetControlStates();
+ pWindow->FreeResources(true);
+ }
+ UnloadNotOnDemandWindows();
+
+ m_vecMsgTargets.erase( m_vecMsgTargets.begin(), m_vecMsgTargets.end() );
+
+ // destroy our custom windows...
+ for (int i = 0; i < (int)m_vecCustomWindows.size(); i++)
+ {
+ CGUIWindow *pWindow = m_vecCustomWindows[i];
+ Remove(pWindow->GetID());
+ delete pWindow;
+ }
+
+ // clear our vectors of windows
+ m_vecCustomWindows.clear();
+ m_activeDialogs.clear();
+}
+
+/// \brief Route to a window
+/// \param pWindow Window to route to
+void CGUIWindowManager::RouteToWindow(CGUIWindow* dialog)
+{
+ // Just to be sure: Unroute this window,
+ // #we may have routed to it before
+ RemoveDialog(dialog->GetID());
+
+ m_activeDialogs.push_back(dialog);
+}
+
+/// \brief Unroute window
+/// \param id ID of the window routed
+void CGUIWindowManager::RemoveDialog(int id)
+{
+ for (iDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
+ {
+ if ((*it)->GetID() == id)
+ {
+ m_activeDialogs.erase(it);
+ return;
+ }
+ }
+}
+
+bool CGUIWindowManager::HasModalDialog() const
+{
+ for (ciDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
+ {
+ CGUIWindow *window = *it;
+ if (window->IsModalDialog())
+ { // have a modal window
+ if (!window->IsAnimating(ANIM_TYPE_WINDOW_CLOSE))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CGUIWindowManager::HasDialogOnScreen() const
+{
+ return (m_activeDialogs.size() > 0);
+}
+
+/// \brief Get the ID of the top most routed window
+/// \return id ID of the window or WINDOW_INVALID if no routed window available
+int CGUIWindowManager::GetTopMostModalDialogID() const
+{
+ for (crDialog it = m_activeDialogs.rbegin(); it != m_activeDialogs.rend(); ++it)
+ {
+ CGUIWindow *dialog = *it;
+ if (dialog->IsModalDialog())
+ { // have a modal window
+ return dialog->GetID();
+ }
+ }
+ return WINDOW_INVALID;
+}
+
+void CGUIWindowManager::SendThreadMessage(CGUIMessage& message)
+{
+ ::EnterCriticalSection(&m_critSection );
+
+ CGUIMessage* msg = new CGUIMessage(message);
+ m_vecThreadMessages.push_back( pair<CGUIMessage*,int>(msg,0) );
+
+ ::LeaveCriticalSection(&m_critSection );
+}
+
+void CGUIWindowManager::SendThreadMessage(CGUIMessage& message, int window)
+{
+ ::EnterCriticalSection(&m_critSection );
+
+ CGUIMessage* msg = new CGUIMessage(message);
+ m_vecThreadMessages.push_back( pair<CGUIMessage*,int>(msg,window) );
+
+ ::LeaveCriticalSection(&m_critSection );
+}
+
+void CGUIWindowManager::DispatchThreadMessages()
+{
+ ::EnterCriticalSection(&m_critSection );
+ vector< pair<CGUIMessage*,int> > messages(m_vecThreadMessages);
+ m_vecThreadMessages.erase(m_vecThreadMessages.begin(), m_vecThreadMessages.end());
+ ::LeaveCriticalSection(&m_critSection );
+
+ while ( messages.size() > 0 )
+ {
+ vector< pair<CGUIMessage*,int> >::iterator it = messages.begin();
+ CGUIMessage* pMsg = it->first;
+ int window = it->second;
+ // first remove the message from the queue,
+ // else the message could be processed more then once
+ it = messages.erase(it);
+
+ if (window)
+ SendMessage( *pMsg, window );
+ else
+ SendMessage( *pMsg );
+ delete pMsg;
+ }
+}
+
+void CGUIWindowManager::AddMsgTarget( IMsgTargetCallback* pMsgTarget )
+{
+ m_vecMsgTargets.push_back( pMsgTarget );
+}
+
+int CGUIWindowManager::GetActiveWindow() const
+{
+ if (!m_windowHistory.empty())
+ return m_windowHistory.top();
+ return WINDOW_INVALID;
+}
+
+// same as GetActiveWindow() except it first grabs dialogs
+int CGUIWindowManager::GetFocusedWindow() const
+{
+ int dialog = GetTopMostModalDialogID();
+ if (dialog != WINDOW_INVALID)
+ return dialog;
+
+ return GetActiveWindow();
+}
+
+bool CGUIWindowManager::IsWindowActive(int id, bool ignoreClosing /* = true */) const
+{
+ // mask out multiple instances of the same window
+ id &= WINDOW_ID_MASK;
+ if ((GetActiveWindow() & WINDOW_ID_MASK) == id) return true;
+ // run through the dialogs
+ for (ciDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
+ {
+ CGUIWindow *window = *it;
+ if ((window->GetID() & WINDOW_ID_MASK) == id && (!ignoreClosing || !window->IsAnimating(ANIM_TYPE_WINDOW_CLOSE)))
+ return true;
+ }
+ return false; // window isn't active
+}
+
+bool CGUIWindowManager::IsWindowActive(const CStdString &xmlFile, bool ignoreClosing /* = true */) const
+{
+ CGUIWindow *window = GetWindow(GetActiveWindow());
+ if (window && CUtil::GetFileName(window->GetXMLFile()).Equals(xmlFile)) return true;
+ // run through the dialogs
+ for (ciDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
+ {
+ CGUIWindow *window = *it;
+ if (CUtil::GetFileName(window->GetXMLFile()).Equals(xmlFile) && (!ignoreClosing || !window->IsAnimating(ANIM_TYPE_WINDOW_CLOSE)))
+ return true;
+ }
+ return false; // window isn't active
+}
+
+bool CGUIWindowManager::IsWindowVisible(int id) const
+{
+ return IsWindowActive(id, false);
+}
+
+bool CGUIWindowManager::IsWindowVisible(const CStdString &xmlFile) const
+{
+ return IsWindowActive(xmlFile, false);
+}
+
+void CGUIWindowManager::LoadNotOnDemandWindows()
+{
+ for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); it++)
+ {
+ CGUIWindow *pWindow = (*it).second;
+ if (!pWindow ->GetLoadOnDemand())
+ {
+ pWindow->FreeResources(true);
+ pWindow->Initialize();
+ }
+ }
+}
+
+void CGUIWindowManager::UnloadNotOnDemandWindows()
+{
+ for (WindowMap::iterator it = m_mapWindows.begin(); it != m_mapWindows.end(); it++)
+ {
+ CGUIWindow *pWindow = (*it).second;
+ if (!pWindow->GetLoadOnDemand())
+ {
+ pWindow->FreeResources(true);
+ }
+ }
+}
+
+bool CGUIWindowManager::IsOverlayAllowed() const
+{
+ return m_bShowOverlay;
+}
+
+void CGUIWindowManager::ShowOverlay(CGUIWindow::OVERLAY_STATE state)
+{
+ if (state != CGUIWindow::OVERLAY_STATE_PARENT_WINDOW)
+ m_bShowOverlay = state == CGUIWindow::OVERLAY_STATE_SHOWN;
+}
+
+void CGUIWindowManager::HideOverlay(CGUIWindow::OVERLAY_STATE state)
+{
+ if (state == CGUIWindow::OVERLAY_STATE_HIDDEN)
+ m_bShowOverlay = false;
+}
+
+void CGUIWindowManager::AddToWindowHistory(int newWindowID)
+{
+ // Check the window stack to see if this window is in our history,
+ // and if so, pop all the other windows off the stack so that we
+ // always have a predictable "Back" behaviour for each window
+ stack<int> historySave = m_windowHistory;
+ while (historySave.size())
+ {
+ if (historySave.top() == newWindowID)
+ break;
+ historySave.pop();
+ }
+ if (!historySave.empty())
+ { // found window in history
+ m_windowHistory = historySave;
+ }
+ else
+ { // didn't find window in history - add it to the stack
+ m_windowHistory.push(newWindowID);
+ }
+}
+
+void CGUIWindowManager::GetActiveModelessWindows(vector<int> &ids)
+{
+ // run through our modeless windows, and construct a vector of them
+ // useful for saving and restoring the modeless windows on skin change etc.
+ for (iDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
+ {
+ if (!(*it)->IsModalDialog())
+ ids.push_back((*it)->GetID());
+ }
+}
+
+CGUIWindow *CGUIWindowManager::GetTopMostDialog() const
+{
+ // find the window with the lowest render order
+ vector<CGUIWindow *> renderList = m_activeDialogs;
+ stable_sort(renderList.begin(), renderList.end(), RenderOrderSortFunction);
+
+ if (!renderList.size())
+ return NULL;
+
+ // return the last window in the list
+ return *renderList.rbegin();
+}
+
+bool CGUIWindowManager::IsWindowTopMost(int id) const
+{
+ CGUIWindow *topMost = GetTopMostDialog();
+ if (topMost && (topMost->GetID() & WINDOW_ID_MASK) == id)
+ return true;
+ return false;
+}
+
+bool CGUIWindowManager::IsWindowTopMost(const CStdString &xmlFile) const
+{
+ CGUIWindow *topMost = GetTopMostDialog();
+ if (topMost && CUtil::GetFileName(topMost->GetXMLFile()).Equals(xmlFile))
+ return true;
+ return false;
+}
+
+void CGUIWindowManager::ClearWindowHistory()
+{
+ while (m_windowHistory.size())
+ m_windowHistory.pop();
+}
+
+#ifdef _DEBUG
+void CGUIWindowManager::DumpTextureUse()
+{
+ CGUIWindow* pWindow = GetWindow(GetActiveWindow());
+ if (pWindow)
+ pWindow->DumpTextureUse();
+
+ for (iDialog it = m_activeDialogs.begin(); it != m_activeDialogs.end(); ++it)
+ {
+ if ((*it)->IsDialogRunning())
+ (*it)->DumpTextureUse();
+ }
+}
+#endif
diff --git a/guilib/GUIWindowManager.h b/guilib/GUIWindowManager.h
new file mode 100644
index 0000000000..8120e89562
--- /dev/null
+++ b/guilib/GUIWindowManager.h
@@ -0,0 +1,142 @@
+/*!
+\file GUIWindowManager.h
+\brief
+*/
+
+#ifndef GUILIB_CGUIWindowManager_H
+#define GUILIB_CGUIWindowManager_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIWindow.h"
+#include "IMsgSenderCallback.h"
+#include "IWindowManagerCallback.h"
+#include "IMsgTargetCallback.h"
+
+class CGUIDialog;
+
+#define WINDOW_ID_MASK 0xffff
+
+/*!
+ \ingroup winman
+ \brief
+ */
+class CGUIWindowManager: public IMsgSenderCallback
+{
+public:
+ CGUIWindowManager(void);
+ virtual ~CGUIWindowManager(void);
+ bool SendMessage(CGUIMessage& message);
+ bool SendMessage(CGUIMessage& message, int window);
+ void Initialize();
+ void Add(CGUIWindow* pWindow);
+ void AddUniqueInstance(CGUIWindow *window);
+ void AddCustomWindow(CGUIWindow* pWindow);
+ void Remove(int id);
+ void Delete(int id);
+ void ActivateWindow(int iWindowID, const CStdString &strPath = "");
+ void ChangeActiveWindow(int iNewID, const CStdString &strPath = "");
+ void ActivateWindow(int iWindowID, const std::vector<CStdString>& params, bool swappingWindows = false);
+ void PreviousWindow();
+ void RefreshWindow();
+ void LoadNotOnDemandWindows();
+ void UnloadNotOnDemandWindows();
+
+ void CloseDialogs(bool forceClose = false);
+
+ // OnAction() runs through our active dialogs and windows and sends the message
+ // off to the callbacks (application, python, playlist player) and to the
+ // currently focused window(s). Returns true only if the message is handled.
+ bool OnAction(const CAction &action);
+
+ void Render();
+ void RenderDialogs();
+ CGUIWindow* GetWindow(int id) const;
+ void Process(bool renderOnly = false);
+ void SetCallback(IWindowManagerCallback& callback);
+ void DeInitialize();
+
+ void RouteToWindow(CGUIWindow* dialog);
+ void AddModeless(CGUIWindow* dialog);
+ void RemoveDialog(int id);
+ int GetTopMostModalDialogID() const;
+
+ void SendThreadMessage(CGUIMessage& message);
+ void SendThreadMessage(CGUIMessage& message, int window);
+ void DispatchThreadMessages();
+ void AddMsgTarget( IMsgTargetCallback* pMsgTarget );
+ int GetActiveWindow() const;
+ int GetFocusedWindow() const;
+ bool HasModalDialog() const;
+ bool HasDialogOnScreen() const;
+ void UpdateModelessVisibility();
+ bool IsWindowActive(int id, bool ignoreClosing = true) const;
+ bool IsWindowVisible(int id) const;
+ bool IsWindowTopMost(int id) const;
+ bool IsWindowActive(const CStdString &xmlFile, bool ignoreClosing = true) const;
+ bool IsWindowVisible(const CStdString &xmlFile) const;
+ bool IsWindowTopMost(const CStdString &xmlFile) const;
+ bool IsOverlayAllowed() const;
+ void ShowOverlay(CGUIWindow::OVERLAY_STATE state);
+ void GetActiveModelessWindows(std::vector<int> &ids);
+#ifdef _DEBUG
+ void DumpTextureUse();
+#endif
+private:
+ void HideOverlay(CGUIWindow::OVERLAY_STATE state);
+ void AddToWindowHistory(int newWindowID);
+ void ClearWindowHistory();
+ CGUIWindow *GetTopMostDialog() const;
+
+ friend class CApplicationMessenger;
+ void ActivateWindow_Internal(int windowID, const std::vector<CStdString> &params, bool swappingWindows);
+ void Process_Internal(bool renderOnly = false);
+ void Render_Internal();
+
+ typedef std::map<int, CGUIWindow *> WindowMap;
+ WindowMap m_mapWindows;
+ std::vector <CGUIWindow*> m_vecCustomWindows;
+ std::vector <CGUIWindow*> m_activeDialogs;
+ typedef std::vector<CGUIWindow*>::iterator iDialog;
+ typedef std::vector<CGUIWindow*>::const_iterator ciDialog;
+ typedef std::vector<CGUIWindow*>::reverse_iterator rDialog;
+ typedef std::vector<CGUIWindow*>::const_reverse_iterator crDialog;
+
+ std::stack<int> m_windowHistory;
+
+ IWindowManagerCallback* m_pCallback;
+ std::vector < std::pair<CGUIMessage*,int> > m_vecThreadMessages;
+ CRITICAL_SECTION m_critSection;
+ std::vector <IMsgTargetCallback*> m_vecMsgTargets;
+
+ bool m_bShowOverlay;
+};
+
+/*!
+ \ingroup winman
+ \brief
+ */
+extern CGUIWindowManager m_gWindowManager;
+#endif
+
diff --git a/guilib/GUIWrappingListContainer.cpp b/guilib/GUIWrappingListContainer.cpp
new file mode 100644
index 0000000000..80170ca5b6
--- /dev/null
+++ b/guilib/GUIWrappingListContainer.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIWrappingListContainer.h"
+#include "FileItem.h"
+#include "Key.h"
+#include "utils/log.h"
+
+CGUIWrappingListContainer::CGUIWrappingListContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, int scrollTime, int preloadItems, int fixedPosition)
+ : CGUIBaseContainer(parentID, controlID, posX, posY, width, height, orientation, scrollTime, preloadItems)
+{
+ m_cursor = fixedPosition;
+ ControlType = GUICONTAINER_WRAPLIST;
+ m_type = VIEW_TYPE_LIST;
+ m_extraItems = 0;
+}
+
+CGUIWrappingListContainer::~CGUIWrappingListContainer(void)
+{
+}
+
+void CGUIWrappingListContainer::UpdatePageControl(int offset)
+{
+ if (m_pageControl)
+ { // tell our pagecontrol (scrollbar or whatever) to update (offset it by our cursor position)
+ CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), m_pageControl, CorrectOffset(offset, m_cursor));
+ SendWindowMessage(msg);
+ }
+}
+
+bool CGUIWrappingListContainer::OnAction(const CAction &action)
+{
+ switch (action.id)
+ {
+ case ACTION_PAGE_UP:
+ Scroll(-m_itemsPerPage);
+ return true;
+ case ACTION_PAGE_DOWN:
+ Scroll(m_itemsPerPage);
+ return true;
+ // smooth scrolling (for analog controls)
+ case ACTION_SCROLL_UP:
+ {
+ m_analogScrollCount += action.amount1 * action.amount1;
+ bool handled = false;
+ while (m_analogScrollCount > 0.4)
+ {
+ handled = true;
+ m_analogScrollCount -= 0.4f;
+ Scroll(-1);
+ }
+ return handled;
+ }
+ break;
+ case ACTION_SCROLL_DOWN:
+ {
+ m_analogScrollCount += action.amount1 * action.amount1;
+ bool handled = false;
+ while (m_analogScrollCount > 0.4)
+ {
+ handled = true;
+ m_analogScrollCount -= 0.4f;
+ Scroll(1);
+ }
+ return handled;
+ }
+ break;
+ }
+ return CGUIBaseContainer::OnAction(action);
+}
+
+bool CGUIWrappingListContainer::OnMessage(CGUIMessage& message)
+{
+ if (message.GetControlId() == GetID() )
+ {
+ if (message.GetMessage() == GUI_MSG_ITEM_SELECT)
+ {
+ SelectItem(message.GetParam1());
+ return true;
+ }
+ else if (message.GetMessage() == GUI_MSG_PAGE_CHANGE)
+ {
+ if (message.GetSenderId() == m_pageControl && IsVisible())
+ { // offset by our cursor position
+ message.SetParam1(message.GetParam1() - m_cursor);
+ }
+ }
+ }
+ return CGUIBaseContainer::OnMessage(message);
+}
+
+bool CGUIWrappingListContainer::MoveUp(bool wrapAround)
+{
+ Scroll(-1);
+ return true;
+}
+
+bool CGUIWrappingListContainer::MoveDown(bool wrapAround)
+{
+ Scroll(+1);
+ return true;
+}
+
+// scrolls the said amount
+void CGUIWrappingListContainer::Scroll(int amount)
+{
+ ScrollToOffset(m_offset + amount);
+}
+
+void CGUIWrappingListContainer::ValidateOffset()
+{
+ if (m_itemsPerPage <= (int)m_items.size())
+ return;
+
+ // no need to check the range here, but we need to check we have
+ // more items than slots.
+ ResetExtraItems();
+ if (m_items.size())
+ {
+ unsigned int numItems = m_items.size();
+ while (m_items.size() < (unsigned int)m_itemsPerPage)
+ {
+ // add additional copies of items, as we require extras at render time
+ for (unsigned int i = 0; i < numItems; i++)
+ {
+ if (m_items[i]->IsFileItem())
+ m_items.push_back(CFileItemPtr(new CFileItem(*(CFileItem *)m_items[i].get())));
+ else
+ m_items.push_back(CGUIListItemPtr(new CGUIListItem(*m_items[i])));
+ m_extraItems++;
+ }
+ }
+ }
+}
+
+int CGUIWrappingListContainer::CorrectOffset(int offset, int cursor) const
+{
+ if (m_items.size())
+ {
+ int correctOffset = (offset + cursor) % (int)m_items.size();
+ if (correctOffset < 0) correctOffset += m_items.size();
+ return correctOffset;
+ }
+ return 0;
+}
+
+int CGUIWrappingListContainer::GetSelectedItem() const
+{
+ if (m_items.size() > m_extraItems)
+ {
+ int numItems = (int)(m_items.size() - m_extraItems);
+ int correctOffset = (m_offset + m_cursor) % numItems;
+ if (correctOffset < 0) correctOffset += numItems;
+ return correctOffset;
+ }
+ return 0;
+}
+
+bool CGUIWrappingListContainer::SelectItemFromPoint(const CPoint &point)
+{
+ if (!m_focusedLayout || !m_layout)
+ return false;
+
+ const float mouse_scroll_speed = 0.05f;
+ const float mouse_max_amount = 1.0f; // max speed: 1 item per frame
+ float sizeOfItem = m_layout->Size(m_orientation);
+ // see if the point is either side of our focused item
+ float start = m_cursor * sizeOfItem;
+ float end = start + m_focusedLayout->Size(m_orientation);
+ float pos = (m_orientation == VERTICAL) ? point.y : point.x;
+ if (pos < start - 0.5f * sizeOfItem)
+ { // scroll backward
+ if (!InsideLayout(m_layout, point))
+ return false;
+ float amount = std::min((start - pos) / sizeOfItem, mouse_max_amount);
+ m_analogScrollCount += amount * amount * mouse_scroll_speed;
+ CLog::Log(LOGERROR, "%s: Speed %f", __FUNCTION__, amount);
+ if (m_analogScrollCount > 1)
+ {
+ Scroll(-1);
+ m_analogScrollCount-=1.0f;
+ }
+ return true;
+ }
+ else if (pos > end + 0.5f * sizeOfItem)
+ { // scroll forward
+ if (!InsideLayout(m_layout, point))
+ return false;
+
+ float amount = std::min((pos - end) / sizeOfItem, mouse_max_amount);
+ m_analogScrollCount += amount * amount * mouse_scroll_speed;
+ if (m_analogScrollCount > 1)
+ {
+ Scroll(1);
+ m_analogScrollCount-=1.0f;
+ }
+ return true;
+ }
+ return InsideLayout(m_focusedLayout, point);
+}
+
+void CGUIWrappingListContainer::SelectItem(int item)
+{
+ if (item >= 0 && item < (int)m_items.size())
+ ScrollToOffset(item - m_cursor);
+}
+
+void CGUIWrappingListContainer::ResetExtraItems()
+{
+ // delete any extra items
+ if (m_extraItems)
+ m_items.erase(m_items.begin() + m_items.size() - m_extraItems, m_items.end());
+ m_extraItems = 0;
+}
+
+void CGUIWrappingListContainer::Reset()
+{
+ ResetExtraItems();
+ CGUIBaseContainer::Reset();
+}
+
+int CGUIWrappingListContainer::GetCurrentPage() const
+{
+ int offset = CorrectOffset(m_offset, m_cursor);
+ if (offset + m_itemsPerPage - m_cursor >= (int)GetRows()) // last page
+ return (GetRows() + m_itemsPerPage - 1) / m_itemsPerPage;
+ return offset / m_itemsPerPage + 1;
+}
+
+void CGUIWrappingListContainer::SetPageControlRange()
+{
+ if (m_pageControl)
+ {
+ CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), m_pageControl, m_itemsPerPage, m_items.size() + m_itemsPerPage - 1);
+ SendWindowMessage(msg);
+ }
+}
diff --git a/guilib/GUIWrappingListContainer.h b/guilib/GUIWrappingListContainer.h
new file mode 100644
index 0000000000..7f2f8edea8
--- /dev/null
+++ b/guilib/GUIWrappingListContainer.h
@@ -0,0 +1,62 @@
+/*!
+\file GUIListContainer.h
+\brief
+*/
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIBaseContainer.h"
+/*!
+ \ingroup controls
+ \brief
+ */
+class CGUIWrappingListContainer : public CGUIBaseContainer
+{
+public:
+ CGUIWrappingListContainer(int parentID, int controlID, float posX, float posY, float width, float height, ORIENTATION orientation, int scrollTime, int preloadItems, int fixedPosition);
+ virtual ~CGUIWrappingListContainer(void);
+ virtual CGUIWrappingListContainer *Clone() const { return new CGUIWrappingListContainer(*this); };
+
+ virtual bool OnAction(const CAction &action);
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual int GetSelectedItem() const;
+
+protected:
+ virtual void Scroll(int amount);
+ virtual bool MoveDown(bool wrapAround);
+ virtual bool MoveUp(bool wrapAround);
+ virtual void ValidateOffset();
+ virtual int CorrectOffset(int offset, int cursor) const;
+ virtual bool SelectItemFromPoint(const CPoint &point);
+ virtual void SelectItem(int item);
+ virtual void Reset();
+ virtual unsigned int GetNumItems() const { return m_items.size() - m_extraItems; };
+ virtual int GetCurrentPage() const;
+ virtual void SetPageControlRange();
+ virtual void UpdatePageControl(int offset);
+
+ void ResetExtraItems();
+ unsigned int m_extraItems;
+};
+
diff --git a/guilib/Geometry.h b/guilib/Geometry.h
new file mode 100644
index 0000000000..2de87d2d64
--- /dev/null
+++ b/guilib/Geometry.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#pragma once
+
+#ifdef __GNUC__
+// under gcc, inline will only take place if optimizations are applied (-O). this will force inline even whith optimizations.
+#define XBMC_FORCE_INLINE __attribute__((always_inline))
+#else
+#define XBMC_FORCE_INLINE
+#endif
+
+
+class CPoint
+{
+public:
+ CPoint()
+ {
+ x = 0; y = 0;
+ };
+
+ CPoint(float a, float b)
+ {
+ x = a;
+ y = b;
+ };
+
+ CPoint operator+(const CPoint &point) const
+ {
+ CPoint ans;
+ ans.x = x + point.x;
+ ans.y = y + point.y;
+ return ans;
+ };
+
+ const CPoint &operator+=(const CPoint &point)
+ {
+ x += point.x;
+ y += point.y;
+ return *this;
+ };
+
+ CPoint operator-(const CPoint &point) const
+ {
+ CPoint ans;
+ ans.x = x - point.x;
+ ans.y = y - point.y;
+ return ans;
+ };
+
+ const CPoint &operator-=(const CPoint &point)
+ {
+ x -= point.x;
+ y -= point.y;
+ return *this;
+ };
+
+ float x, y;
+};
+
+class CRect
+{
+public:
+ CRect() { x1 = y1 = x2 = y2 = 0;};
+ CRect(float left, float top, float right, float bottom) { x1 = left; y1 = top; x2 = right; y2 = bottom; };
+
+ void SetRect(float left, float top, float right, float bottom) { x1 = left; y1 = top; x2 = right; y2 = bottom; };
+
+ bool PtInRect(const CPoint &point) const
+ {
+ if (x1 <= point.x && point.x <= x2 && y1 <= point.y && point.y <= y2)
+ return true;
+ return false;
+ };
+
+ inline const CRect &operator -=(const CPoint &point) XBMC_FORCE_INLINE
+ {
+ x1 -= point.x;
+ y1 -= point.y;
+ x2 -= point.x;
+ y2 -= point.y;
+ return *this;
+ };
+
+ inline const CRect &operator +=(const CPoint &point) XBMC_FORCE_INLINE
+ {
+ x1 += point.x;
+ y1 += point.y;
+ x2 += point.x;
+ y2 += point.y;
+ return *this;
+ };
+
+ const CRect &Intersect(const CRect &rect)
+ {
+ if (rect.x2 < x2) x2 = rect.x2;
+ if (rect.y2 < y2) y2 = rect.y2;
+ if (rect.x1 > x1) x1 = rect.x1;
+ if (rect.y1 > y1) y1 = rect.y1;
+ if (x1 > x2) x1 = x2;
+ if (y1 > y2) y1 = y2;
+ return *this;
+ };
+
+ inline bool IsEmpty() const XBMC_FORCE_INLINE
+ {
+ return (x2 - x1) * (y2 - y1) == 0;
+ };
+
+ inline float Width() const XBMC_FORCE_INLINE
+ {
+ return x2 - x1;
+ };
+
+ inline float Height() const XBMC_FORCE_INLINE
+ {
+ return y2 - y1;
+ };
+
+ bool operator !=(const CRect &rect) const
+ {
+ if (x1 != rect.x1) return true;
+ if (x2 != rect.x2) return true;
+ if (y1 != rect.y1) return true;
+ if (y2 != rect.y2) return true;
+ return false;
+ };
+
+ float x1, y1, x2, y2;
+};
+
diff --git a/guilib/GraphicContext.cpp b/guilib/GraphicContext.cpp
new file mode 100644
index 0000000000..5c094a6562
--- /dev/null
+++ b/guilib/GraphicContext.cpp
@@ -0,0 +1,797 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "GraphicContext.h"
+#include "GUIFontManager.h"
+#include "GUIMessage.h"
+#include "IMsgSenderCallback.h"
+#include "utils/SingleLock.h"
+#include "Application.h"
+#include "GUISettings.h"
+#include "Settings.h"
+#include "AdvancedSettings.h"
+#include "cores/VideoRenderers/RenderManager.h"
+#include "WindowingFactory.h"
+#include "SkinInfo.h"
+#include "TextureManager.h"
+#include "MouseStat.h"
+
+using namespace std;
+
+CGraphicContext g_graphicsContext;
+extern bool g_fullScreen;
+
+/* quick access to a skin setting, fine unless we starts clearing video settings */
+static CSettingInt* g_guiSkinzoom = NULL;
+
+CGraphicContext::CGraphicContext(void)
+{
+ m_iScreenWidth = 720;
+ m_iScreenHeight = 576;
+ m_iScreenId = 0;
+ m_strMediaDir = "";
+ m_bCalibrating = false;
+ m_Resolution = RES_INVALID;
+ m_pCallback = NULL;
+ m_guiScaleX = m_guiScaleY = 1.0f;
+ m_windowResolution = RES_INVALID;
+ m_bFullScreenRoot = false;
+}
+
+CGraphicContext::~CGraphicContext(void)
+{
+}
+
+bool CGraphicContext::SendMessage(int message, int senderID, int destID, int param1, int param2)
+{
+ if (!m_pCallback) return false;
+ CGUIMessage msg(message, senderID, destID, param1, param2);
+ return m_pCallback->SendMessage(msg);
+}
+
+bool CGraphicContext::SendMessage(CGUIMessage& message)
+{
+ if (!m_pCallback) return false;
+ return m_pCallback->SendMessage(message);
+}
+
+void CGraphicContext::setMessageSender(IMsgSenderCallback* pCallback)
+{
+ m_pCallback = pCallback;
+}
+
+void CGraphicContext::SetOrigin(float x, float y)
+{
+ if (m_origins.size())
+ m_origins.push(CPoint(x,y) + m_origins.top());
+ else
+ m_origins.push(CPoint(x,y));
+
+ AddTransform(TransformMatrix::CreateTranslation(x, y));
+}
+
+void CGraphicContext::RestoreOrigin()
+{
+ m_origins.pop();
+ RemoveTransform();
+}
+
+// add a new clip region, intersecting with the previous clip region.
+bool CGraphicContext::SetClipRegion(float x, float y, float w, float h)
+{ // transform from our origin
+ CPoint origin;
+ if (m_origins.size())
+ origin = m_origins.top();
+
+ // ok, now intersect with our old clip region
+ CRect rect(x, y, x + w, y + h);
+ rect += origin;
+ if (m_clipRegions.size())
+ {
+ // intersect with original clip region
+ rect.Intersect(m_clipRegions.top());
+ }
+
+ if (rect.IsEmpty())
+ return false;
+
+ m_clipRegions.push(rect);
+
+ // here we could set the hardware clipping, if applicable
+ return true;
+}
+
+void CGraphicContext::RestoreClipRegion()
+{
+ if (m_clipRegions.size())
+ m_clipRegions.pop();
+
+ // here we could reset the hardware clipping, if applicable
+}
+
+void CGraphicContext::ClipRect(CRect &vertex, CRect &texture, CRect *texture2)
+{
+ // this is the software clipping routine. If the graphics hardware is set to do the clipping
+ // (eg via SetClipPlane in D3D for instance) then this routine is unneeded.
+ if (m_clipRegions.size())
+ {
+ // take a copy of the vertex rectangle and intersect
+ // it with our clip region (moved to the same coordinate system)
+ CRect clipRegion(m_clipRegions.top());
+ if (m_origins.size())
+ clipRegion -= m_origins.top();
+ CRect original(vertex);
+ vertex.Intersect(clipRegion);
+ // and use the original to compute the texture coordinates
+ if (original != vertex)
+ {
+ float scaleX = texture.Width() / original.Width();
+ float scaleY = texture.Height() / original.Height();
+ texture.x1 += (vertex.x1 - original.x1) * scaleX;
+ texture.y1 += (vertex.y1 - original.y1) * scaleY;
+ texture.x2 += (vertex.x2 - original.x2) * scaleX;
+ texture.y2 += (vertex.y2 - original.y2) * scaleY;
+ if (texture2)
+ {
+ scaleX = texture2->Width() / original.Width();
+ scaleY = texture2->Height() / original.Height();
+ texture2->x1 += (vertex.x1 - original.x1) * scaleX;
+ texture2->y1 += (vertex.y1 - original.y1) * scaleY;
+ texture2->x2 += (vertex.x2 - original.x2) * scaleX;
+ texture2->y2 += (vertex.y2 - original.y2) * scaleY;
+ }
+ }
+ }
+}
+
+bool CGraphicContext::SetViewPort(float fx, float fy, float fwidth, float fheight, bool intersectPrevious /* = false */)
+{
+ CRect oldviewport;
+ g_Windowing.GetViewPort(oldviewport);
+
+ // transform coordinates - we may have a rotation which changes the positioning of the
+ // minimal and maximal viewport extents. We currently go to the maximal extent.
+ float x[4], y[4];
+ x[0] = x[3] = fx;
+ x[1] = x[2] = fx + fwidth;
+ y[0] = y[1] = fy;
+ y[2] = y[3] = fy + fheight;
+ float minX = (float)m_iScreenWidth;
+ float maxX = 0;
+ float minY = (float)m_iScreenHeight;
+ float maxY = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ float z = 0;
+ ScaleFinalCoords(x[i], y[i], z);
+ if (x[i] < minX) minX = x[i];
+ if (x[i] > maxX) maxX = x[i];
+ if (y[i] < minY) minY = y[i];
+ if (y[i] > maxY) maxY = y[i];
+ }
+
+ int newLeft = (int)(minX + 0.5f);
+ int newTop = (int)(minY + 0.5f);
+ int newRight = (int)(maxX + 0.5f);
+ int newBottom = (int)(maxY + 0.5f);
+ if (intersectPrevious)
+ {
+ // do the intersection
+ int oldLeft = (int)oldviewport.x1;
+ int oldTop = (int)oldviewport.y1;
+ int oldRight = (int)oldviewport.x2;
+ int oldBottom = (int)oldviewport.y2;
+ if (newLeft >= oldRight || newTop >= oldBottom || newRight <= oldLeft || newBottom <= oldTop)
+ { // empty intersection - return false to indicate no rendering should occur
+ return false;
+ }
+ // ok, they intersect, do the intersection
+ if (newLeft < oldLeft) newLeft = oldLeft;
+ if (newTop < oldTop) newTop = oldTop;
+ if (newRight > oldRight) newRight = oldRight;
+ if (newBottom > oldBottom) newBottom = oldBottom;
+ }
+ // check range against screen size
+ if (newRight <= 0 || newBottom <= 0 ||
+ newTop >= m_iScreenHeight || newLeft >= m_iScreenWidth ||
+ newLeft >= newRight || newTop >= newBottom)
+ { // no intersection with the screen
+ return false;
+ }
+ // intersection with the screen
+ if (newLeft < 0) newLeft = 0;
+ if (newTop < 0) newTop = 0;
+ if (newRight > m_iScreenWidth) newRight = m_iScreenWidth;
+ if (newBottom > m_iScreenHeight) newBottom = m_iScreenHeight;
+
+ ASSERT(newLeft < newRight);
+ ASSERT(newTop < newBottom);
+
+ CRect newviewport((float)newLeft, (float)newTop, (float)newRight, (float)newBottom);
+ g_Windowing.SetViewPort(newviewport);
+
+ m_viewStack.push(oldviewport);
+
+ UpdateCameraPosition(m_cameras.top());
+ return true;
+}
+
+void CGraphicContext::RestoreViewPort()
+{
+ if (!m_viewStack.size()) return;
+
+ CRect oldviewport = m_viewStack.top();
+ g_Windowing.SetViewPort(oldviewport);
+
+ m_viewStack.pop();
+
+ UpdateCameraPosition(m_cameras.top());
+}
+
+const RECT& CGraphicContext::GetViewWindow() const
+{
+ return m_videoRect;
+}
+
+void CGraphicContext::SetViewWindow(float left, float top, float right, float bottom)
+{
+ if (m_bCalibrating)
+ {
+ SetFullScreenViewWindow(m_Resolution);
+ }
+ else
+ {
+ m_videoRect.left = (long)(ScaleFinalXCoord(left, top) + 0.5f);
+ m_videoRect.top = (long)(ScaleFinalYCoord(left, top) + 0.5f);
+ m_videoRect.right = (long)(ScaleFinalXCoord(right, bottom) + 0.5f);
+ m_videoRect.bottom = (long)(ScaleFinalYCoord(right, bottom) + 0.5f);
+ }
+}
+
+void CGraphicContext::SetFullScreenViewWindow(RESOLUTION &res)
+{
+ m_videoRect.left = g_settings.m_ResInfo[res].Overscan.left;
+ m_videoRect.top = g_settings.m_ResInfo[res].Overscan.top;
+ m_videoRect.right = g_settings.m_ResInfo[res].Overscan.right;
+ m_videoRect.bottom = g_settings.m_ResInfo[res].Overscan.bottom;
+}
+
+void CGraphicContext::SetFullScreenVideo(bool bOnOff)
+{
+ Lock();
+ m_bFullScreenVideo = bOnOff;
+
+#if defined(HAS_VIDEO_PLAYBACK)
+ if(m_bFullScreenRoot)
+ {
+ if(m_bFullScreenVideo)
+ g_graphicsContext.SetVideoResolution(g_renderManager.GetResolution());
+ else if(g_guiSettings.m_LookAndFeelResolution > RES_DESKTOP)
+ g_graphicsContext.SetVideoResolution(g_guiSettings.m_LookAndFeelResolution);
+ else
+ g_graphicsContext.SetVideoResolution(RES_DESKTOP);
+ }
+ else
+ g_graphicsContext.SetVideoResolution(RES_WINDOW);
+#endif
+
+ SetFullScreenViewWindow(m_Resolution);
+ Unlock();
+}
+
+bool CGraphicContext::IsFullScreenVideo() const
+{
+ return m_bFullScreenVideo;
+}
+
+bool CGraphicContext::IsCalibrating() const
+{
+ return m_bCalibrating;
+}
+
+void CGraphicContext::SetCalibrating(bool bOnOff)
+{
+ m_bCalibrating = bOnOff;
+}
+
+bool CGraphicContext::IsValidResolution(RESOLUTION res)
+{
+ if (res >= RES_WINDOW && (size_t) res <= g_settings.m_ResInfo.size())
+ {
+ return true;
+ }
+
+ return false;
+}
+
+void CGraphicContext::SetVideoResolution(RESOLUTION res, bool forceUpdate)
+{
+ RESOLUTION lastRes = m_Resolution;
+
+ // If the user asked us to guess, go with desktop
+ if (res == RES_AUTORES || !IsValidResolution(res))
+ {
+ res = RES_DESKTOP;
+ }
+
+ // If we are switching to the same resolution and same window/full-screen, no need to do anything
+ if (!forceUpdate && res == lastRes && m_bFullScreenRoot == g_advancedSettings.m_fullScreen)
+ {
+ return;
+ }
+
+ if (res >= RES_DESKTOP || g_advancedSettings.m_startFullScreen)
+ {
+ g_advancedSettings.m_fullScreen = true;
+ m_bFullScreenRoot = true;
+ }
+ else
+ {
+ g_advancedSettings.m_fullScreen = false;
+ m_bFullScreenRoot = false;
+ }
+
+ Lock();
+
+ m_iScreenWidth = g_settings.m_ResInfo[res].iWidth;
+ m_iScreenHeight = g_settings.m_ResInfo[res].iHeight;
+ m_iScreenId = g_settings.m_ResInfo[res].iScreen;
+ m_Resolution = res;
+
+ if (g_advancedSettings.m_fullScreen)
+ {
+ bool blankOtherDisplays = g_guiSettings.GetInt("videoscreen.displayblanking") == BLANKING_ALL_DISPLAYS;
+ g_Windowing.SetFullScreen(true, g_settings.m_ResInfo[res], blankOtherDisplays);
+ }
+ else if (lastRes >= RES_DESKTOP )
+ g_Windowing.SetFullScreen(false, g_settings.m_ResInfo[res], false);
+ else
+ g_Windowing.ResizeWindow(m_iScreenWidth, m_iScreenHeight, -1, -1);
+
+ // set the mouse resolution
+ g_renderManager.Recover();
+ g_Mouse.SetResolution(m_iScreenWidth, m_iScreenHeight, 1, 1);
+ g_fontManager.ReloadTTFFonts();
+
+ SetFullScreenViewWindow(res);
+
+ Unlock();
+}
+
+RESOLUTION CGraphicContext::GetVideoResolution() const
+{
+ return m_Resolution;
+}
+
+void CGraphicContext::ResetOverscan(RESOLUTION_INFO &res)
+{
+ res.Overscan.left = 0;
+ res.Overscan.top = 0;
+ res.Overscan.right = res.iWidth;
+ res.Overscan.bottom = res.iHeight;
+}
+
+void CGraphicContext::ResetOverscan(RESOLUTION res, OVERSCAN &overscan)
+{
+ overscan.left = 0;
+ overscan.top = 0;
+ switch (res)
+ {
+ case RES_HDTV_1080i:
+ overscan.right = 1920;
+ overscan.bottom = 1080;
+ break;
+ case RES_HDTV_720p:
+ overscan.right = 1280;
+ overscan.bottom = 720;
+ break;
+ case RES_HDTV_480p_16x9:
+ case RES_HDTV_480p_4x3:
+ case RES_NTSC_16x9:
+ case RES_NTSC_4x3:
+ case RES_PAL60_16x9:
+ case RES_PAL60_4x3:
+ overscan.right = 720;
+ overscan.bottom = 480;
+ break;
+ case RES_PAL_16x9:
+ case RES_PAL_4x3:
+ overscan.right = 720;
+ overscan.bottom = 576;
+ break;
+ default:
+ overscan.right = g_settings.m_ResInfo[res].iWidth;
+ overscan.bottom = g_settings.m_ResInfo[res].iHeight;
+ break;
+ }
+}
+
+void CGraphicContext::ResetScreenParameters(RESOLUTION res)
+{
+ // For now these are all on the first screen.
+ g_settings.m_ResInfo[res].iScreen = 0;
+
+ // 1080i
+ switch (res)
+ {
+ case RES_HDTV_1080i:
+ g_settings.m_ResInfo[res].iSubtitles = (int)(0.965 * 1080);
+ g_settings.m_ResInfo[res].iWidth = 1920;
+ g_settings.m_ResInfo[res].iHeight = 1080;
+ g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_INTERLACED | D3DPRESENTFLAG_WIDESCREEN;
+ g_settings.m_ResInfo[res].fPixelRatio = 1.0f;
+ g_settings.m_ResInfo[res].strMode ="1080i 16:9";
+ break;
+ case RES_HDTV_720p:
+ g_settings.m_ResInfo[res].iSubtitles = (int)(0.965 * 720);
+ g_settings.m_ResInfo[res].iWidth = 1280;
+ g_settings.m_ResInfo[res].iHeight = 720;
+ g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_PROGRESSIVE | D3DPRESENTFLAG_WIDESCREEN;
+ g_settings.m_ResInfo[res].fPixelRatio = 1.0f;
+ g_settings.m_ResInfo[res].strMode = "720p 16:9";
+ break;
+ case RES_HDTV_480p_4x3:
+ g_settings.m_ResInfo[res].iSubtitles = (int)(0.9 * 480);
+ g_settings.m_ResInfo[res].iWidth = 720;
+ g_settings.m_ResInfo[res].iHeight = 480;
+ g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_PROGRESSIVE;
+ g_settings.m_ResInfo[res].fPixelRatio = 4320.0f / 4739.0f;
+ g_settings.m_ResInfo[res].strMode = "480p 4:3";
+ break;
+ case RES_HDTV_480p_16x9:
+ g_settings.m_ResInfo[res].iSubtitles = (int)(0.965 * 480);
+ g_settings.m_ResInfo[res].iWidth = 720;
+ g_settings.m_ResInfo[res].iHeight = 480;
+ g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_PROGRESSIVE | D3DPRESENTFLAG_WIDESCREEN;
+ g_settings.m_ResInfo[res].fPixelRatio = 4320.0f / 4739.0f*4.0f / 3.0f;
+ g_settings.m_ResInfo[res].strMode = "480p 16:9";
+ break;
+ case RES_NTSC_4x3:
+ g_settings.m_ResInfo[res].iSubtitles = (int)(0.9 * 480);
+ g_settings.m_ResInfo[res].iWidth = 720;
+ g_settings.m_ResInfo[res].iHeight = 480;
+ g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_INTERLACED;
+ g_settings.m_ResInfo[res].fPixelRatio = 4320.0f / 4739.0f;
+ g_settings.m_ResInfo[res].strMode = "NTSC 4:3";
+ break;
+ case RES_NTSC_16x9:
+ g_settings.m_ResInfo[res].iSubtitles = (int)(0.965 * 480);
+ g_settings.m_ResInfo[res].iWidth = 720;
+ g_settings.m_ResInfo[res].iHeight = 480;
+ g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_INTERLACED | D3DPRESENTFLAG_WIDESCREEN;
+ g_settings.m_ResInfo[res].fPixelRatio = 4320.0f / 4739.0f*4.0f / 3.0f;
+ g_settings.m_ResInfo[res].strMode = "NTSC 16:9";
+ break;
+ case RES_PAL_4x3:
+ g_settings.m_ResInfo[res].iSubtitles = (int)(0.9 * 576);
+ g_settings.m_ResInfo[res].iWidth = 720;
+ g_settings.m_ResInfo[res].iHeight = 576;
+ g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_INTERLACED;
+ g_settings.m_ResInfo[res].fPixelRatio = 128.0f / 117.0f;
+ g_settings.m_ResInfo[res].strMode = "PAL 4:3";
+ break;
+ case RES_PAL_16x9:
+ g_settings.m_ResInfo[res].iSubtitles = (int)(0.965 * 576);
+ g_settings.m_ResInfo[res].iWidth = 720;
+ g_settings.m_ResInfo[res].iHeight = 576;
+ g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_INTERLACED | D3DPRESENTFLAG_WIDESCREEN;
+ g_settings.m_ResInfo[res].fPixelRatio = 128.0f / 117.0f*4.0f / 3.0f;
+ g_settings.m_ResInfo[res].strMode = "PAL 16:9";
+ break;
+ case RES_PAL60_4x3:
+ g_settings.m_ResInfo[res].iSubtitles = (int)(0.9 * 480);
+ g_settings.m_ResInfo[res].iWidth = 720;
+ g_settings.m_ResInfo[res].iHeight = 480;
+ g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_INTERLACED;
+ g_settings.m_ResInfo[res].fPixelRatio = 4320.0f / 4739.0f;
+ g_settings.m_ResInfo[res].strMode = "PAL60 4:3";
+ break;
+ case RES_PAL60_16x9:
+ g_settings.m_ResInfo[res].iSubtitles = (int)(0.965 * 480);
+ g_settings.m_ResInfo[res].iWidth = 720;
+ g_settings.m_ResInfo[res].iHeight = 480;
+ g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_INTERLACED | D3DPRESENTFLAG_WIDESCREEN;
+ g_settings.m_ResInfo[res].fPixelRatio = 4320.0f / 4739.0f*4.0f / 3.0f;
+ g_settings.m_ResInfo[res].strMode = "PAL60 16:9";
+ break;
+ default:
+ break;
+ }
+ ResetOverscan(res, g_settings.m_ResInfo[res].Overscan);
+}
+
+float CGraphicContext::GetPixelRatio(RESOLUTION iRes) const
+{
+ if (iRes >= 0 && iRes < (int)g_settings.m_ResInfo.size())
+ return g_settings.m_ResInfo[iRes].fPixelRatio;
+ return 0.0f;
+}
+
+void CGraphicContext::Clear()
+{
+ g_Windowing.ClearBuffers(0, 0, 0, 0);
+}
+
+void CGraphicContext::CaptureStateBlock()
+{
+ g_Windowing.CaptureStateBlock();
+}
+
+void CGraphicContext::ApplyStateBlock()
+{
+ g_Windowing.ApplyStateBlock();
+}
+
+void CGraphicContext::SetScalingResolution(RESOLUTION res, float posX, float posY, bool needsScaling)
+{
+ Lock();
+ m_windowResolution = res;
+ if (needsScaling && m_Resolution != RES_INVALID)
+ {
+ // calculate necessary scalings
+ float fFromWidth;
+ float fFromHeight;
+ float fToPosX;
+ float fToPosY;
+ float fToWidth;
+ float fToHeight;
+
+ {
+ fFromWidth = (float)g_settings.m_ResInfo[res].iWidth;
+ fFromHeight = (float)g_settings.m_ResInfo[res].iHeight;
+ fToPosX = (float)g_settings.m_ResInfo[m_Resolution].Overscan.left;
+ fToPosY = (float)g_settings.m_ResInfo[m_Resolution].Overscan.top;
+ fToWidth = (float)g_settings.m_ResInfo[m_Resolution].Overscan.right - fToPosX;
+ fToHeight = (float)g_settings.m_ResInfo[m_Resolution].Overscan.bottom - fToPosY;
+ }
+
+ // add additional zoom to compensate for any overskan built in skin
+ float fZoom = g_SkinInfo.GetSkinZoom();
+
+ if(!g_guiSkinzoom) // lookup gui setting if we didn't have it already
+ g_guiSkinzoom = (CSettingInt*)g_guiSettings.GetSetting("lookandfeel.skinzoom");
+
+ if(g_guiSkinzoom)
+ fZoom *= (100 + g_guiSkinzoom->GetData()) * 0.01f;
+
+ fZoom -= 1.0f;
+ fToPosX -= fToWidth * fZoom * 0.5f;
+ fToWidth *= fZoom + 1.0f;
+
+ // adjust for aspect ratio as zoom is given in the vertical direction and we don't
+ // do aspect ratio corrections in the gui code
+ fZoom = fZoom / g_settings.m_ResInfo[m_Resolution].fPixelRatio;
+ fToPosY -= fToHeight * fZoom * 0.5f;
+ fToHeight *= fZoom + 1.0f;
+
+ m_guiScaleX = fFromWidth / fToWidth;
+ m_guiScaleY = fFromHeight / fToHeight;
+ TransformMatrix windowOffset = TransformMatrix::CreateTranslation(posX, posY);
+ TransformMatrix guiScaler = TransformMatrix::CreateScaler(fToWidth / fFromWidth, fToHeight / fFromHeight, fToHeight / fFromHeight);
+ TransformMatrix guiOffset = TransformMatrix::CreateTranslation(fToPosX, fToPosY);
+ m_guiTransform = guiOffset * guiScaler * windowOffset;
+ }
+ else
+ {
+ m_guiTransform = TransformMatrix::CreateTranslation(posX, posY);
+ m_guiScaleX = 1.0f;
+ m_guiScaleY = 1.0f;
+ }
+ // reset our origin and camera
+ while (m_origins.size())
+ m_origins.pop();
+ m_origins.push(CPoint(posX, posY));
+ while (m_cameras.size())
+ m_cameras.pop();
+ m_cameras.push(CPoint(0.5f*m_iScreenWidth, 0.5f*m_iScreenHeight));
+
+ // and reset the final transform
+ UpdateFinalTransform(m_guiTransform);
+ Unlock();
+}
+
+void CGraphicContext::SetRenderingResolution(RESOLUTION res, float posX, float posY, bool needsScaling)
+{
+ Lock();
+ SetScalingResolution(res, posX, posY, needsScaling);
+ UpdateCameraPosition(m_cameras.top());
+ Unlock();
+}
+
+void CGraphicContext::UpdateFinalTransform(const TransformMatrix &matrix)
+{
+ m_finalTransform = matrix;
+ // We could set the world transform here to GPU-ize the animation system.
+ // trouble is that we require the resulting x,y coords to be rounded to
+ // the nearest pixel (vertex shader perhaps?)
+}
+
+void CGraphicContext::InvertFinalCoords(float &x, float &y) const
+{
+ m_finalTransform.InverseTransformPosition(x, y);
+}
+
+float CGraphicContext::GetScalingPixelRatio() const
+{
+ if (m_Resolution == m_windowResolution)
+ return GetPixelRatio(m_windowResolution);
+
+ RESOLUTION checkRes = m_windowResolution;
+ if (checkRes == RES_INVALID)
+ checkRes = m_Resolution;
+ // resolutions are different - we want to return the aspect ratio of the video resolution
+ // but only once it's been corrected for the skin -> screen coordinates scaling
+ float winWidth = (float)g_settings.m_ResInfo[checkRes].iWidth;
+ float winHeight = (float)g_settings.m_ResInfo[checkRes].iHeight;
+ float outWidth = (float)g_settings.m_ResInfo[m_Resolution].iWidth;
+ float outHeight = (float)g_settings.m_ResInfo[m_Resolution].iHeight;
+ float outPR = GetPixelRatio(m_Resolution);
+
+ return outPR * (outWidth / outHeight) / (winWidth / winHeight);
+}
+
+void CGraphicContext::SetCameraPosition(const CPoint &camera)
+{
+ // offset the camera from our current location (this is in XML coordinates) and scale it up to
+ // the screen resolution
+ CPoint cam(camera);
+ if (m_origins.size())
+ cam += m_origins.top();
+
+ RESOLUTION windowRes = (m_windowResolution == RES_INVALID) ? m_Resolution : m_windowResolution;
+ cam.x *= (float)m_iScreenWidth / g_settings.m_ResInfo[windowRes].iWidth;
+ cam.y *= (float)m_iScreenHeight / g_settings.m_ResInfo[windowRes].iHeight;
+
+ m_cameras.push(cam);
+ UpdateCameraPosition(m_cameras.top());
+}
+
+void CGraphicContext::RestoreCameraPosition()
+{ // remove the top camera from the stack
+ ASSERT(m_cameras.size());
+ m_cameras.pop();
+ UpdateCameraPosition(m_cameras.top());
+}
+
+// NOTE: This routine is currently called (twice) every time there is a <camera>
+// tag in the skin. It actually only has to be called before we render
+// something, so another option is to just save the camera coordinates
+// and then have a routine called before every draw that checks whether
+// the camera has changed, and if so, changes it. Similarly, it could set
+// the world transform at that point as well (or even combine world + view
+// to cut down on one setting)
+void CGraphicContext::UpdateCameraPosition(const CPoint &camera)
+{
+ g_Windowing.SetCameraPosition(camera, m_iScreenWidth, m_iScreenHeight);
+}
+
+bool CGraphicContext::RectIsAngled(float x1, float y1, float x2, float y2) const
+{ // need only test 3 points, as they must be co-planer
+ if (m_finalTransform.TransformZCoord(x1, y1, 0)) return true;
+ if (m_finalTransform.TransformZCoord(x2, y2, 0)) return true;
+ if (m_finalTransform.TransformZCoord(x1, y2, 0)) return true;
+ return false;
+}
+
+float CGraphicContext::GetFPS() const
+{
+ if (m_Resolution != RES_INVALID)
+ {
+ if (g_settings.m_ResInfo[m_Resolution].fRefreshRate > 0)
+ return g_settings.m_ResInfo[m_Resolution].fRefreshRate;
+ if (m_Resolution == RES_PAL_4x3 || m_Resolution == RES_PAL_16x9)
+ return 50.0f;
+ if (m_Resolution == RES_HDTV_1080i)
+ return 30.0f;
+ }
+ return 60.0f;
+}
+
+void CGraphicContext::BeginPaint(bool lock)
+{
+ if (lock) Lock();
+}
+
+void CGraphicContext::EndPaint(bool lock)
+{
+ if (lock) Unlock();
+}
+
+bool CGraphicContext::IsFullScreenRoot () const
+{
+ return m_bFullScreenRoot;
+}
+
+bool CGraphicContext::ToggleFullScreenRoot ()
+{
+ RESOLUTION newRes;
+
+ if (m_bFullScreenRoot)
+ {
+ newRes = RES_WINDOW;
+ }
+ else
+ {
+ if (g_guiSettings.m_LookAndFeelResolution > RES_DESKTOP)
+ newRes = g_guiSettings.m_LookAndFeelResolution;
+ else
+ newRes = RES_DESKTOP;
+
+#if defined(HAS_VIDEO_PLAYBACK)
+ if (g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating())
+ {
+ /* we need to trick renderer that we are fullscreen already so it gives us a valid value */
+ m_bFullScreenRoot = true;
+ newRes = g_renderManager.GetResolution();
+ m_bFullScreenRoot = false;
+ }
+#endif
+
+ }
+
+ SetVideoResolution(newRes);
+
+ return m_bFullScreenRoot;
+}
+
+void CGraphicContext::SetMediaDir(const CStdString &strMediaDir)
+{
+ g_TextureManager.SetTexturePath(strMediaDir);
+ m_strMediaDir = strMediaDir;
+}
+
+void CGraphicContext::Flip()
+{
+ g_Windowing.PresentRender();
+}
+
+void CGraphicContext::ApplyHardwareTransform()
+{
+ g_Windowing.ApplyHardwareTransform(m_finalTransform);
+}
+
+void CGraphicContext::RestoreHardwareTransform()
+{
+ g_Windowing.RestoreHardwareTransform();
+}
+
+void CGraphicContext::NotifyAppFocusChange(bool bGaining)
+{
+ g_Windowing.NotifyAppFocusChange(bGaining);
+}
+
+void CGraphicContext::ClipToViewWindow()
+{
+}
+
+void CGraphicContext::GetAllowedResolutions(vector<RESOLUTION> &res)
+{
+ res.clear();
+
+ res.push_back(RES_WINDOW);
+ res.push_back(RES_DESKTOP);
+ for (size_t r = (size_t) RES_CUSTOM; r < g_settings.m_ResInfo.size(); r++)
+ {
+ res.push_back((RESOLUTION) r);
+ }
+}
+
diff --git a/guilib/GraphicContext.h b/guilib/GraphicContext.h
new file mode 100644
index 0000000000..1d2adf03f7
--- /dev/null
+++ b/guilib/GraphicContext.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+/*!
+\file GraphicContext.h
+\brief
+*/
+
+#ifndef GUILIB_GRAPHICCONTEXT_H
+#define GUILIB_GRAPHICCONTEXT_H
+
+#pragma once
+
+#ifdef __GNUC__
+// under gcc, inline will only take place if optimizations are applied (-O). this will force inline even whith optimizations.
+#define XBMC_FORCE_INLINE __attribute__((always_inline))
+#else
+#define XBMC_FORCE_INLINE
+#endif
+
+
+#include <vector>
+#include <stack>
+#include <map>
+#include "utils/CriticalSection.h" // base class
+#include "TransformMatrix.h" // for the members m_guiTransform etc.
+#include "Geometry.h" // for CRect/CPoint
+#include "gui3d.h"
+#include "StdString.h"
+#include "Resolution.h"
+
+// forward definitions
+class IMsgSenderCallback;
+class CGUIMessage;
+
+enum VIEW_TYPE { VIEW_TYPE_NONE = 0,
+ VIEW_TYPE_LIST,
+ VIEW_TYPE_ICON,
+ VIEW_TYPE_BIG_LIST,
+ VIEW_TYPE_BIG_ICON,
+ VIEW_TYPE_WIDE,
+ VIEW_TYPE_BIG_WIDE,
+ VIEW_TYPE_WRAP,
+ VIEW_TYPE_BIG_WRAP,
+ VIEW_TYPE_AUTO,
+ VIEW_TYPE_MAX };
+
+
+class CGraphicContext : public CCriticalSection
+{
+public:
+ CGraphicContext(void);
+ virtual ~CGraphicContext(void);
+
+ // the following two functions should wrap any
+ // GL calls to maintain thread safety
+ void BeginPaint(bool lock=true);
+ void EndPaint(bool lock=true);
+
+ int GetWidth() const { return m_iScreenWidth; }
+ int GetHeight() const { return m_iScreenHeight; }
+ float GetFPS() const;
+ bool SendMessage(CGUIMessage& message);
+ bool SendMessage(int message, int senderID, int destID, int param1 = 0, int param2 = 0);
+ void setMessageSender(IMsgSenderCallback* pCallback);
+ const CStdString& GetMediaDir() const { return m_strMediaDir; }
+ void SetMediaDir(const CStdString& strMediaDir);
+ bool IsWidescreen() const { return m_bWidescreen; }
+ bool SetViewPort(float fx, float fy , float fwidth, float fheight, bool intersectPrevious = false);
+ void RestoreViewPort();
+ const RECT& GetViewWindow() const;
+ void SetViewWindow(float left, float top, float right, float bottom);
+ void SetFullScreenViewWindow(RESOLUTION &res);
+ bool IsFullScreenRoot() const;
+ bool ToggleFullScreenRoot();
+ void SetFullScreenVideo(bool bOnOff);
+ bool IsFullScreenVideo() const;
+ bool IsCalibrating() const;
+ void SetCalibrating(bool bOnOff);
+ bool IsValidResolution(RESOLUTION res);
+ void SetVideoResolution(RESOLUTION res, bool forceUpdate = false);
+ RESOLUTION GetVideoResolution() const;
+ void ResetOverscan(RESOLUTION res, OVERSCAN &overscan);
+ void ResetOverscan(RESOLUTION_INFO &resinfo);
+ void ResetScreenParameters(RESOLUTION res);
+ void Lock() { EnterCriticalSection(*this); }
+ void Unlock() { LeaveCriticalSection(*this); }
+ float GetPixelRatio(RESOLUTION iRes) const;
+ void CaptureStateBlock();
+ void ApplyStateBlock();
+ void Clear();
+ void GetAllowedResolutions(std::vector<RESOLUTION> &res);
+
+ // output scaling
+ void SetRenderingResolution(RESOLUTION res, float posX, float posY, bool needsScaling); ///< Sets scaling up for rendering
+ void SetScalingResolution(RESOLUTION res, float posX, float posY, bool needsScaling); ///< Sets scaling up for skin loading etc.
+ float GetScalingPixelRatio() const;
+ void Flip();
+ void InvertFinalCoords(float &x, float &y) const;
+ inline float ScaleFinalXCoord(float x, float y) const XBMC_FORCE_INLINE { return m_finalTransform.TransformXCoord(x, y, 0); }
+ inline float ScaleFinalYCoord(float x, float y) const XBMC_FORCE_INLINE { return m_finalTransform.TransformYCoord(x, y, 0); }
+ inline float ScaleFinalZCoord(float x, float y) const XBMC_FORCE_INLINE { return m_finalTransform.TransformZCoord(x, y, 0); }
+ inline void ScaleFinalCoords(float &x, float &y, float &z) const XBMC_FORCE_INLINE { m_finalTransform.TransformPosition(x, y, z); }
+ bool RectIsAngled(float x1, float y1, float x2, float y2) const;
+
+ inline float GetGUIScaleX() const XBMC_FORCE_INLINE { return m_guiScaleX; }
+ inline float GetGUIScaleY() const XBMC_FORCE_INLINE { return m_guiScaleY; }
+ inline color_t MergeAlpha(color_t color) const XBMC_FORCE_INLINE
+ {
+ color_t alpha = m_finalTransform.TransformAlpha((color >> 24) & 0xff);
+ if (alpha > 255) alpha = 255;
+ return ((alpha << 24) & 0xff000000) | (color & 0xffffff);
+ }
+
+ void SetOrigin(float x, float y);
+ void RestoreOrigin();
+ void SetCameraPosition(const CPoint &camera);
+ void RestoreCameraPosition();
+ bool SetClipRegion(float x, float y, float w, float h);
+ void RestoreClipRegion();
+ void ApplyHardwareTransform();
+ void RestoreHardwareTransform();
+ void NotifyAppFocusChange(bool bGaining);
+ void ClipRect(CRect &vertex, CRect &texture, CRect *diffuse = NULL);
+ void ClipToViewWindow();
+ inline void ResetWindowTransform()
+ {
+ while (m_groupTransform.size())
+ m_groupTransform.pop();
+ m_groupTransform.push(m_guiTransform);
+ }
+ inline void AddTransform(const TransformMatrix &matrix)
+ {
+ ASSERT(m_groupTransform.size());
+ if (m_groupTransform.size())
+ m_groupTransform.push(m_groupTransform.top() * matrix);
+ else
+ m_groupTransform.push(matrix);
+ UpdateFinalTransform(m_groupTransform.top());
+ }
+ inline void RemoveTransform()
+ {
+ ASSERT(m_groupTransform.size() > 1);
+ if (m_groupTransform.size())
+ m_groupTransform.pop();
+ if (m_groupTransform.size())
+ UpdateFinalTransform(m_groupTransform.top());
+ else
+ UpdateFinalTransform(TransformMatrix());
+ }
+
+protected:
+ IMsgSenderCallback* m_pCallback;
+ std::stack<CRect> m_viewStack;
+
+ int m_iScreenHeight;
+ int m_iScreenWidth;
+ int m_iScreenId;
+ int m_iBackBufferCount;
+ bool m_bWidescreen;
+ CStdString m_strMediaDir;
+ RECT m_videoRect;
+ bool m_bFullScreenRoot;
+ bool m_bFullScreenVideo;
+ bool m_bCalibrating;
+ RESOLUTION m_Resolution;
+
+private:
+ void UpdateCameraPosition(const CPoint &camera);
+ void UpdateFinalTransform(const TransformMatrix &matrix);
+ RESOLUTION m_windowResolution;
+ float m_guiScaleX;
+ float m_guiScaleY;
+ std::stack<CPoint> m_cameras;
+ std::stack<CPoint> m_origins;
+ std::stack<CRect> m_clipRegions;
+
+ TransformMatrix m_guiTransform;
+ TransformMatrix m_finalTransform;
+ std::stack<TransformMatrix> m_groupTransform;
+};
+
+/*!
+ \ingroup graphics
+ \brief
+ */
+extern CGraphicContext g_graphicsContext;
+#endif
diff --git a/guilib/IAudioDeviceChangedCallback.h b/guilib/IAudioDeviceChangedCallback.h
new file mode 100644
index 0000000000..c9d55b7a23
--- /dev/null
+++ b/guilib/IAudioDeviceChangedCallback.h
@@ -0,0 +1,31 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+class IAudioDeviceChangedCallback
+{
+public:
+ virtual void Initialize(int iDevice)=0;
+ virtual void DeInitialize(int iDevice)=0;
+ virtual ~IAudioDeviceChangedCallback() {}
+};
+
diff --git a/guilib/IMsgSenderCallback.h b/guilib/IMsgSenderCallback.h
new file mode 100644
index 0000000000..3f825d4469
--- /dev/null
+++ b/guilib/IMsgSenderCallback.h
@@ -0,0 +1,45 @@
+/*!
+\file IMsgSenderCallback.h
+\brief
+*/
+
+#ifndef GUILIB_IMSGSENDERCALLBACK
+#define GUILIB_IMSGSENDERCALLBACK
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIMessage.h"
+
+/*!
+ \ingroup winman
+ \brief
+ */
+class IMsgSenderCallback
+{
+public:
+ virtual bool SendMessage(CGUIMessage& message) = 0;
+ virtual ~IMsgSenderCallback() {}
+};
+
+#endif
diff --git a/guilib/IMsgTargetCallback.h b/guilib/IMsgTargetCallback.h
new file mode 100644
index 0000000000..7af60fded2
--- /dev/null
+++ b/guilib/IMsgTargetCallback.h
@@ -0,0 +1,45 @@
+/*!
+\file IMsgTargetCallback.h
+\brief
+*/
+
+#ifndef GUILIB_IMSGTARGETCALLBACK
+#define GUILIB_IMSGTARGETCALLBACK
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GUIMessage.h"
+
+/*!
+ \ingroup winman
+ \brief
+ */
+class IMsgTargetCallback
+{
+public:
+ virtual bool OnMessage(CGUIMessage& message) = 0;
+ virtual ~IMsgTargetCallback() {}
+};
+
+#endif
diff --git a/guilib/IWindowManagerCallback.cpp b/guilib/IWindowManagerCallback.cpp
new file mode 100644
index 0000000000..a47634c498
--- /dev/null
+++ b/guilib/IWindowManagerCallback.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "IWindowManagerCallback.h"
+
+
+IWindowManagerCallback::IWindowManagerCallback(void)
+{}
+
+IWindowManagerCallback::~IWindowManagerCallback(void)
+{}
diff --git a/guilib/IWindowManagerCallback.h b/guilib/IWindowManagerCallback.h
new file mode 100644
index 0000000000..25391b228c
--- /dev/null
+++ b/guilib/IWindowManagerCallback.h
@@ -0,0 +1,42 @@
+/*!
+\file IWindowManagerCallback.h
+\brief
+*/
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+/*!
+ \ingroup winman
+ \brief
+ */
+class IWindowManagerCallback
+{
+public:
+ IWindowManagerCallback(void);
+ virtual ~IWindowManagerCallback(void);
+
+ virtual void FrameMove() = 0;
+ virtual void Render() = 0;
+ virtual void Process() = 0;
+};
diff --git a/guilib/Key.cpp b/guilib/Key.cpp
new file mode 100644
index 0000000000..7d19a2a47d
--- /dev/null
+++ b/guilib/Key.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "Key.h"
+
+CKey::CKey(void)
+{
+ m_buttonCode = KEY_INVALID;
+ m_leftTrigger = 0;
+ m_rightTrigger = 0;
+ m_leftThumbX = 0.0f;
+ m_leftThumbY = 0.0f;
+ m_rightThumbX = 0.0f;
+ m_rightThumbY = 0.0f;
+ m_repeat = 0.0f;
+ m_fromHttpApi = false;
+ m_held = 0;
+}
+
+CKey::~CKey(void)
+{}
+
+CKey::CKey(uint32_t buttonCode, uint8_t leftTrigger, uint8_t rightTrigger, float leftThumbX, float leftThumbY, float rightThumbX, float rightThumbY, float repeat)
+{
+ m_leftTrigger = leftTrigger;
+ m_rightTrigger = rightTrigger;
+ m_leftThumbX = leftThumbX;
+ m_leftThumbY = leftThumbY;
+ m_rightThumbX = rightThumbX;
+ m_rightThumbY = rightThumbY;
+ m_buttonCode = buttonCode;
+ m_repeat = repeat;
+ m_fromHttpApi = false;
+ m_held = 0;
+}
+
+CKey::CKey(const CKey& key)
+{
+ *this = key;
+}
+
+uint32_t CKey::GetButtonCode() const // for backwards compatibility only
+{
+ return m_buttonCode;
+}
+
+uint32_t CKey::GetUnicode() const
+{
+ if (m_buttonCode>=KEY_ASCII && m_buttonCode < KEY_UNICODE) // will need to change when Unicode is fully implemented
+ return m_buttonCode-KEY_ASCII;
+ else
+ return 0;
+}
+
+const CKey& CKey::operator=(const CKey& key)
+{
+ if (&key == this) return * this;
+ m_leftTrigger = key.m_leftTrigger;
+ m_rightTrigger = key.m_rightTrigger;
+ m_buttonCode = key.m_buttonCode;
+ m_leftThumbX = key.m_leftThumbX;
+ m_leftThumbY = key.m_leftThumbY;
+ m_rightThumbX = key.m_rightThumbX;
+ m_rightThumbY = key.m_rightThumbY;
+ m_repeat = key.m_repeat;
+ m_fromHttpApi = key.m_fromHttpApi;
+ m_held = key.m_held;
+ return *this;
+}
+
+BYTE CKey::GetLeftTrigger() const
+{
+ return m_leftTrigger;
+}
+
+BYTE CKey::GetRightTrigger() const
+{
+ return m_rightTrigger;
+}
+
+float CKey::GetLeftThumbX() const
+{
+ return m_leftThumbX;
+}
+
+float CKey::GetLeftThumbY() const
+{
+ return m_leftThumbY;
+}
+
+
+float CKey::GetRightThumbX() const
+{
+ return m_rightThumbX;
+}
+
+float CKey::GetRightThumbY() const
+{
+ return m_rightThumbY;
+}
+
+bool CKey::FromKeyboard() const
+{
+ return (m_buttonCode >= KEY_VKEY && m_buttonCode != KEY_INVALID);
+}
+
+bool CKey::IsAnalogButton() const
+{
+ if ((GetButtonCode() > 261 && GetButtonCode() < 270) || (GetButtonCode() > 279 && GetButtonCode() < 284))
+ return true;
+
+ return false;
+}
+
+bool CKey::IsIRRemote() const
+{
+ if (GetButtonCode() < 256)
+ return true;
+ return false;
+}
+
+float CKey::GetRepeat() const
+{
+ return m_repeat;
+}
+
+bool CKey::GetFromHttpApi() const
+{
+ return m_fromHttpApi;
+}
+
+void CKey::SetFromHttpApi(bool bFromHttpApi)
+{
+ m_fromHttpApi = bFromHttpApi;
+}
+
+void CKey::SetHeld(unsigned int held)
+{
+ m_held = held;
+}
+
+unsigned int CKey::GetHeld() const
+{
+ return m_held;
+}
+
diff --git a/guilib/Key.h b/guilib/Key.h
new file mode 100644
index 0000000000..d5328443c0
--- /dev/null
+++ b/guilib/Key.h
@@ -0,0 +1,460 @@
+/*!
+ \file Key.h
+ \brief
+ */
+
+#ifndef GUILIB_KEY
+#define GUILIB_KEY
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "XBIRRemote.h"
+#include <StdString.h>
+
+// Analogue - don't change order
+#define KEY_BUTTON_A 256
+#define KEY_BUTTON_B 257
+#define KEY_BUTTON_X 258
+#define KEY_BUTTON_Y 259
+#define KEY_BUTTON_BLACK 260
+#define KEY_BUTTON_WHITE 261
+#define KEY_BUTTON_LEFT_TRIGGER 262
+#define KEY_BUTTON_RIGHT_TRIGGER 263
+
+#define KEY_BUTTON_LEFT_THUMB_STICK 264
+#define KEY_BUTTON_RIGHT_THUMB_STICK 265
+
+#define KEY_BUTTON_RIGHT_THUMB_STICK_UP 266 // right thumb stick directions
+#define KEY_BUTTON_RIGHT_THUMB_STICK_DOWN 267 // for defining different actions per direction
+#define KEY_BUTTON_RIGHT_THUMB_STICK_LEFT 268
+#define KEY_BUTTON_RIGHT_THUMB_STICK_RIGHT 269
+
+// Digital - don't change order
+#define KEY_BUTTON_DPAD_UP 270
+#define KEY_BUTTON_DPAD_DOWN 271
+#define KEY_BUTTON_DPAD_LEFT 272
+#define KEY_BUTTON_DPAD_RIGHT 273
+
+#define KEY_BUTTON_START 274
+#define KEY_BUTTON_BACK 275
+
+#define KEY_BUTTON_LEFT_THUMB_BUTTON 276
+#define KEY_BUTTON_RIGHT_THUMB_BUTTON 277
+
+#define KEY_BUTTON_LEFT_ANALOG_TRIGGER 278
+#define KEY_BUTTON_RIGHT_ANALOG_TRIGGER 279
+
+#define KEY_BUTTON_LEFT_THUMB_STICK_UP 280 // left thumb stick directions
+#define KEY_BUTTON_LEFT_THUMB_STICK_DOWN 281 // for defining different actions per direction
+#define KEY_BUTTON_LEFT_THUMB_STICK_LEFT 282
+#define KEY_BUTTON_LEFT_THUMB_STICK_RIGHT 283
+
+#define KEY_VMOUSE 0xEFFF
+
+// 0xF000 -> 0xF200 is reserved for the keyboard; a keyboard press is either
+#define KEY_VKEY 0xF000 // a virtual key/functional key e.g. cursor left
+#define KEY_ASCII 0xF100 // a printable character in the range of TRUE ASCII (from 0 to 127) // FIXME make it clean and pure unicode! remove the need for KEY_ASCII
+#define KEY_UNICODE 0xF200 // another printable character whose range is not included in this KEY code
+
+#define KEY_INVALID 0xFFFF
+
+// actions that we have defined...
+#define ACTION_NONE 0
+#define ACTION_MOVE_LEFT 1
+#define ACTION_MOVE_RIGHT 2
+#define ACTION_MOVE_UP 3
+#define ACTION_MOVE_DOWN 4
+#define ACTION_PAGE_UP 5
+#define ACTION_PAGE_DOWN 6
+#define ACTION_SELECT_ITEM 7
+#define ACTION_HIGHLIGHT_ITEM 8
+#define ACTION_PARENT_DIR 9
+#define ACTION_PREVIOUS_MENU 10
+#define ACTION_SHOW_INFO 11
+
+#define ACTION_PAUSE 12
+#define ACTION_STOP 13
+#define ACTION_NEXT_ITEM 14
+#define ACTION_PREV_ITEM 15
+#define ACTION_FORWARD 16 // Can be used to specify specific action in a window, Playback control is handled in ACTION_PLAYER_*
+#define ACTION_REWIND 17 // Can be used to specify specific action in a window, Playback control is handled in ACTION_PLAYER_*
+
+#define ACTION_SHOW_GUI 18 // toggle between GUI and movie or GUI and visualisation.
+#define ACTION_ASPECT_RATIO 19 // toggle quick-access zoom modes. Can b used in videoFullScreen.zml window id=2005
+#define ACTION_STEP_FORWARD 20 // seek +1% in the movie. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_STEP_BACK 21 // seek -1% in the movie. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_BIG_STEP_FORWARD 22 // seek +10% in the movie. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_BIG_STEP_BACK 23 // seek -10% in the movie. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_SHOW_OSD 24 // show/hide OSD. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_SHOW_SUBTITLES 25 // turn subtitles on/off. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_NEXT_SUBTITLE 26 // switch to next subtitle of movie. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_SHOW_CODEC 27 // show information about file. Can b used in videoFullScreen.xml window id=2005 and in slideshow.xml window id=2007
+#define ACTION_NEXT_PICTURE 28 // show next picture of slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_PREV_PICTURE 29 // show previous picture of slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_ZOOM_OUT 30 // zoom in picture during slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_ZOOM_IN 31 // zoom out picture during slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_TOGGLE_SOURCE_DEST 32 // used to toggle between source view and destination view. Can be used in myfiles.xml window id=3
+#define ACTION_SHOW_PLAYLIST 33 // used to toggle between current view and playlist view. Can b used in all mymusic xml files
+#define ACTION_QUEUE_ITEM 34 // used to queue a item to the playlist. Can b used in all mymusic xml files
+#define ACTION_REMOVE_ITEM 35 // not used anymore
+#define ACTION_SHOW_FULLSCREEN 36 // not used anymore
+#define ACTION_ZOOM_LEVEL_NORMAL 37 // zoom 1x picture during slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_ZOOM_LEVEL_1 38 // zoom 2x picture during slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_ZOOM_LEVEL_2 39 // zoom 3x picture during slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_ZOOM_LEVEL_3 40 // zoom 4x picture during slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_ZOOM_LEVEL_4 41 // zoom 5x picture during slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_ZOOM_LEVEL_5 42 // zoom 6x picture during slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_ZOOM_LEVEL_6 43 // zoom 7x picture during slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_ZOOM_LEVEL_7 44 // zoom 8x picture during slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_ZOOM_LEVEL_8 45 // zoom 9x picture during slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_ZOOM_LEVEL_9 46 // zoom 10x picture during slideshow. Can b used in slideshow.xml window id=2007
+
+#define ACTION_CALIBRATE_SWAP_ARROWS 47 // select next arrow. Can b used in: settingsScreenCalibration.xml windowid=11
+#define ACTION_CALIBRATE_RESET 48 // reset calibration to defaults. Can b used in: settingsScreenCalibration.xml windowid=11/settingsUICalibration.xml windowid=10
+#define ACTION_ANALOG_MOVE 49 // analog thumbstick move. Can b used in: slideshow.xml window id=2007/settingsScreenCalibration.xml windowid=11/settingsUICalibration.xml windowid=10
+#define ACTION_ROTATE_PICTURE 50 // rotate current picture during slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_CLOSE_DIALOG 51 // action for closing the dialog. Can b used in any dialog
+#define ACTION_SUBTITLE_DELAY_MIN 52 // Decrease subtitle/movie Delay. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_SUBTITLE_DELAY_PLUS 53 // Increase subtitle/movie Delay. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_AUDIO_DELAY_MIN 54 // Increase avsync delay. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_AUDIO_DELAY_PLUS 55 // Decrease avsync delay. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_AUDIO_NEXT_LANGUAGE 56 // Select next language in movie. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_CHANGE_RESOLUTION 57 // switch 2 next resolution. Can b used during screen calibration settingsScreenCalibration.xml windowid=11
+
+#define REMOTE_0 58 // remote keys 0-9. are used by multiple windows
+#define REMOTE_1 59 // for example in videoFullScreen.xml window id=2005 you can
+#define REMOTE_2 60 // enter time (mmss) to jump to particular point in the movie
+#define REMOTE_3 61
+#define REMOTE_4 62 // with spincontrols you can enter 3digit number to quickly set
+#define REMOTE_5 63 // spincontrol to desired value
+#define REMOTE_6 64
+#define REMOTE_7 65
+#define REMOTE_8 66
+#define REMOTE_9 67
+
+#define ACTION_PLAY 68 // Unused at the moment
+#define ACTION_OSD_SHOW_LEFT 69 // Move left in OSD. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_OSD_SHOW_RIGHT 70 // Move right in OSD. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_OSD_SHOW_UP 71 // Move up in OSD. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_OSD_SHOW_DOWN 72 // Move down in OSD. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_OSD_SHOW_SELECT 73 // toggle/select option in OSD. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_OSD_SHOW_VALUE_PLUS 74 // increase value of current option in OSD. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_OSD_SHOW_VALUE_MIN 75 // decrease value of current option in OSD. Can b used in videoFullScreen.xml window id=2005
+#define ACTION_SMALL_STEP_BACK 76 // jumps a few seconds back during playback of movie. Can b used in videoFullScreen.xml window id=2005
+
+#define ACTION_PLAYER_FORWARD 77 // FF in current file played. global action, can be used anywhere
+#define ACTION_PLAYER_REWIND 78 // RW in current file played. global action, can be used anywhere
+#define ACTION_PLAYER_PLAY 79 // Play current song. Unpauses song and sets playspeed to 1x. global action, can be used anywhere
+
+#define ACTION_DELETE_ITEM 80 // delete current selected item. Can be used in myfiles.xml window id=3 and in myvideoTitle.xml window id=25
+#define ACTION_COPY_ITEM 81 // copy current selected item. Can be used in myfiles.xml window id=3
+#define ACTION_MOVE_ITEM 82 // move current selected item. Can be used in myfiles.xml window id=3
+#define ACTION_SHOW_MPLAYER_OSD 83 // toggles mplayers OSD. Can be used in videofullscreen.xml window id=2005
+#define ACTION_OSD_HIDESUBMENU 84 // removes an OSD sub menu. Can be used in videoOSD.xml window id=2901
+#define ACTION_TAKE_SCREENSHOT 85 // take a screenshot
+#define ACTION_RENAME_ITEM 87 // rename item
+
+#define ACTION_VOLUME_UP 88
+#define ACTION_VOLUME_DOWN 89
+#define ACTION_MUTE 91
+
+#define ACTION_MOUSE 90
+
+#define ACTION_MOUSE_CLICK 100
+#define ACTION_MOUSE_LEFT_CLICK 100
+#define ACTION_MOUSE_RIGHT_CLICK 101
+#define ACTION_MOUSE_MIDDLE_CLICK 102
+#define ACTION_MOUSE_XBUTTON1_CLICK 103
+#define ACTION_MOUSE_XBUTTON2_CLICK 104
+
+#define ACTION_MOUSE_DOUBLE_CLICK 105
+#define ACTION_MOUSE_LEFT_DOUBLE_CLICK 105
+#define ACTION_MOUSE_RIGHT_DOUBLE_CLICK 106
+#define ACTION_MOUSE_MIDDLE_DOUBLE_CLICK 107
+#define ACTION_MOUSE_XBUTTON1_DOUBLE_CLICK 108
+#define ACTION_MOUSE_XBUTTON2_DOUBLE_CLICK 109
+
+#define ACTION_BACKSPACE 110
+#define ACTION_SCROLL_UP 111
+#define ACTION_SCROLL_DOWN 112
+#define ACTION_ANALOG_FORWARD 113
+#define ACTION_ANALOG_REWIND 114
+
+#define ACTION_MOVE_ITEM_UP 115 // move item up in playlist
+#define ACTION_MOVE_ITEM_DOWN 116 // move item down in playlist
+#define ACTION_CONTEXT_MENU 117 // pops up the context menu
+
+
+// stuff for virtual keyboard shortcuts
+#define ACTION_SHIFT 118
+#define ACTION_SYMBOLS 119
+#define ACTION_CURSOR_LEFT 120
+#define ACTION_CURSOR_RIGHT 121
+
+#define ACTION_BUILT_IN_FUNCTION 122
+
+#define ACTION_SHOW_OSD_TIME 123 // displays current time, can be used in videoFullScreen.xml window id=2005
+#define ACTION_ANALOG_SEEK_FORWARD 124 // seeks forward, and displays the seek bar.
+#define ACTION_ANALOG_SEEK_BACK 125 // seeks backward, and displays the seek bar.
+
+#define ACTION_VIS_PRESET_SHOW 126
+#define ACTION_VIS_PRESET_LIST 127
+#define ACTION_VIS_PRESET_NEXT 128
+#define ACTION_VIS_PRESET_PREV 129
+#define ACTION_VIS_PRESET_LOCK 130
+#define ACTION_VIS_PRESET_RANDOM 131
+#define ACTION_VIS_RATE_PRESET_PLUS 132
+#define ACTION_VIS_RATE_PRESET_MINUS 133
+
+#define ACTION_SHOW_VIDEOMENU 134
+#define ACTION_ENTER 135
+
+#define ACTION_INCREASE_RATING 136
+#define ACTION_DECREASE_RATING 137
+
+#define ACTION_NEXT_SCENE 138 // switch to next scene/cutpoint in movie
+#define ACTION_PREV_SCENE 139 // switch to previous scene/cutpoint in movie
+
+#define ACTION_NEXT_LETTER 140 // jump through a list or container by letter
+#define ACTION_PREV_LETTER 141
+
+#define ACTION_JUMP_SMS2 142 // jump direct to a particular letter using SMS-style input
+#define ACTION_JUMP_SMS3 143
+#define ACTION_JUMP_SMS4 144
+#define ACTION_JUMP_SMS5 145
+#define ACTION_JUMP_SMS6 146
+#define ACTION_JUMP_SMS7 147
+#define ACTION_JUMP_SMS8 148
+#define ACTION_JUMP_SMS9 149
+
+#define ACTION_FILTER_CLEAR 150
+#define ACTION_FILTER_SMS2 151
+#define ACTION_FILTER_SMS3 152
+#define ACTION_FILTER_SMS4 153
+#define ACTION_FILTER_SMS5 154
+#define ACTION_FILTER_SMS6 155
+#define ACTION_FILTER_SMS7 156
+#define ACTION_FILTER_SMS8 157
+#define ACTION_FILTER_SMS9 158
+
+#define ACTION_FIRST_PAGE 159
+#define ACTION_LAST_PAGE 160
+
+#define ACTION_AUDIO_DELAY 161
+#define ACTION_SUBTITLE_DELAY 162
+
+#define ACTION_PASTE 180
+#define ACTION_NEXT_CONTROL 181
+#define ACTION_PREV_CONTROL 182
+#define ACTION_CHANNEL_SWITCH 183
+
+#define ACTION_TOGGLE_FULLSCREEN 199 // switch 2 desktop resolution
+#define ACTION_TOGGLE_WATCHED 200 // Toggle watched status (videos)
+#define ACTION_SCAN_ITEM 201 // scan item
+#define ACTION_TOGGLE_DIGITAL_ANALOG 202 // switch digital <-> analog
+#define ACTION_RELOAD_KEYMAPS 203 // reloads CButtonTranslator's keymaps
+#define ACTION_GUIPROFILE_BEGIN 204 // start the GUIControlProfiler running
+
+// Window ID defines to make the code a bit more readable
+#define WINDOW_INVALID 9999
+#define WINDOW_HOME 10000
+#define WINDOW_PROGRAMS 10001
+#define WINDOW_PICTURES 10002
+#define WINDOW_FILES 10003
+#define WINDOW_SETTINGS_MENU 10004
+#define WINDOW_MUSIC 10005 // virtual window to return the music start window.
+#define WINDOW_VIDEOS 10006
+#define WINDOW_SYSTEM_INFORMATION 10007
+#define WINDOW_TEST_PATTERN 10008
+#define WINDOW_SCREEN_CALIBRATION 10011
+
+#define WINDOW_SETTINGS_MYPICTURES 10012
+#define WINDOW_SETTINGS_MYPROGRAMS 10013
+#define WINDOW_SETTINGS_MYWEATHER 10014
+#define WINDOW_SETTINGS_MYMUSIC 10015
+#define WINDOW_SETTINGS_SYSTEM 10016
+#define WINDOW_SETTINGS_MYVIDEOS 10017
+#define WINDOW_SETTINGS_NETWORK 10018
+#define WINDOW_SETTINGS_APPEARANCE 10019
+
+#define WINDOW_SCRIPTS 10020
+#define WINDOW_VIDEO_GENRE 10021
+#define WINDOW_VIDEO_ACTOR 10022
+#define WINDOW_VIDEO_YEAR 10023
+#define WINDOW_VIDEO_FILES 10024
+#define WINDOW_VIDEO_NAV 10025
+#define WINDOW_VIDEO_PLAYLIST 10028
+
+#define WINDOW_LOGIN_SCREEN 10029
+#define WINDOW_SETTINGS_PROFILES 10034
+
+#define WINDOW_DIALOG_YES_NO 10100
+#define WINDOW_DIALOG_PROGRESS 10101
+#define WINDOW_DIALOG_KEYBOARD 10103
+#define WINDOW_DIALOG_VOLUME_BAR 10104
+#define WINDOW_DIALOG_SUB_MENU 10105
+#define WINDOW_DIALOG_CONTEXT_MENU 10106
+#define WINDOW_DIALOG_KAI_TOAST 10107
+#define WINDOW_DIALOG_NUMERIC 10109
+#define WINDOW_DIALOG_GAMEPAD 10110
+#define WINDOW_DIALOG_BUTTON_MENU 10111
+#define WINDOW_DIALOG_MUSIC_SCAN 10112
+#define WINDOW_DIALOG_MUTE_BUG 10113
+#define WINDOW_DIALOG_PLAYER_CONTROLS 10114
+#define WINDOW_DIALOG_SEEK_BAR 10115
+#define WINDOW_DIALOG_MUSIC_OSD 10120
+#define WINDOW_DIALOG_VIS_SETTINGS 10121
+#define WINDOW_DIALOG_VIS_PRESET_LIST 10122
+#define WINDOW_DIALOG_VIDEO_OSD_SETTINGS 10123
+#define WINDOW_DIALOG_AUDIO_OSD_SETTINGS 10124
+#define WINDOW_DIALOG_VIDEO_BOOKMARKS 10125
+#define WINDOW_DIALOG_FILE_BROWSER 10126
+#define WINDOW_DIALOG_NETWORK_SETUP 10128
+#define WINDOW_DIALOG_MEDIA_SOURCE 10129
+#define WINDOW_DIALOG_PROFILE_SETTINGS 10130
+#define WINDOW_DIALOG_LOCK_SETTINGS 10131
+#define WINDOW_DIALOG_CONTENT_SETTINGS 10132
+#define WINDOW_DIALOG_VIDEO_SCAN 10133
+#define WINDOW_DIALOG_FAVOURITES 10134
+#define WINDOW_DIALOG_SONG_INFO 10135
+#define WINDOW_DIALOG_SMART_PLAYLIST_EDITOR 10136
+#define WINDOW_DIALOG_SMART_PLAYLIST_RULE 10137
+#define WINDOW_DIALOG_BUSY 10138
+#define WINDOW_DIALOG_PICTURE_INFO 10139
+#define WINDOW_DIALOG_PLUGIN_SETTINGS 10140
+#define WINDOW_DIALOG_ACCESS_POINTS 10141
+#define WINDOW_DIALOG_FULLSCREEN_INFO 10142
+#define WINDOW_DIALOG_KARAOKE_SONGSELECT 10143
+#define WINDOW_DIALOG_KARAOKE_SELECTOR 10144
+#define WINDOW_DIALOG_SLIDER 10145
+
+#define WINDOW_MUSIC_PLAYLIST 10500
+#define WINDOW_MUSIC_FILES 10501
+#define WINDOW_MUSIC_NAV 10502
+#define WINDOW_MUSIC_PLAYLIST_EDITOR 10503
+
+//#define WINDOW_VIRTUAL_KEYBOARD 11000
+#define WINDOW_DIALOG_SELECT 12000
+#define WINDOW_MUSIC_INFO 12001
+#define WINDOW_DIALOG_OK 12002
+#define WINDOW_VIDEO_INFO 12003
+#define WINDOW_SCRIPTS_INFO 12004
+#define WINDOW_FULLSCREEN_VIDEO 12005
+#define WINDOW_VISUALISATION 12006
+#define WINDOW_SLIDESHOW 12007
+#define WINDOW_DIALOG_FILESTACKING 12008
+#define WINDOW_KARAOKELYRICS 12009
+#define WINDOW_WEATHER 12600
+#define WINDOW_SCREENSAVER 12900
+#define WINDOW_OSD 12901
+
+#define WINDOW_VIDEO_MENU 12902
+#define WINDOW_MUSIC_OVERLAY 12903
+#define WINDOW_VIDEO_OVERLAY 12904
+
+#define WINDOW_STARTUP 12999 // for startup animations
+
+// WINDOW_ID's from 13000 to 13099 reserved for Python
+
+#define WINDOW_PYTHON_START 13000
+#define WINDOW_PYTHON_END 13099
+
+#define ICON_TYPE_NONE 101
+#define ICON_TYPE_PROGRAMS 102
+#define ICON_TYPE_MUSIC 103
+#define ICON_TYPE_PICTURES 104
+#define ICON_TYPE_VIDEOS 105
+#define ICON_TYPE_FILES 106
+#define ICON_TYPE_WEATHER 107
+#define ICON_TYPE_SETTINGS 109
+
+/*!
+ \ingroup actionkeys
+ \brief
+ */
+class CAction
+{
+public:
+ CAction()
+ {
+ id = 0;
+ amount1 = amount2 = repeat = 0;
+ buttonCode = 0;
+ unicode = 0;
+ holdTime = 0;
+ };
+ int id;
+ float amount1;
+ float amount2;
+ float repeat;
+ unsigned int buttonCode;
+ CStdString strAction;
+ wchar_t unicode; // new feature, does not fit into id like ASCII, wouldn't be good design either!? Will be set whenever ASCII is set into id (for backwards compatibility)
+ unsigned int holdTime; ///< Time the key has been held down (in ms)
+};
+
+/*!
+ \ingroup actionkeys
+ \brief
+ */
+class CKey
+{
+public:
+ CKey(void);
+ CKey(uint32_t buttonCode, uint8_t leftTrigger = 0, uint8_t rightTrigger = 0, float leftThumbX = 0.0f, float leftThumbY = 0.0f, float rightThumbX = 0.0f, float rightThumbY = 0.0f, float repeat = 0.0f);
+ CKey(const CKey& key);
+
+ virtual ~CKey(void);
+ const CKey& operator=(const CKey& key);
+ uint32_t GetButtonCode() const; // for backwards compatibility only
+ uint32_t GetUnicode() const; // http api does not really support unicode till now. It only simulates unicode when ascii codes are available:
+ uint8_t GetLeftTrigger() const;
+ uint8_t GetRightTrigger() const;
+ float GetLeftThumbX() const;
+ float GetLeftThumbY() const;
+ float GetRightThumbX() const;
+ float GetRightThumbY() const;
+ float GetRepeat() const;
+ bool FromKeyboard() const;
+ bool IsAnalogButton() const;
+ bool IsIRRemote() const;
+ void SetFromHttpApi(bool);
+ bool GetFromHttpApi() const;
+
+ void SetHeld(unsigned int held);
+ unsigned int GetHeld() const;
+private:
+ uint32_t m_buttonCode;
+ uint8_t m_leftTrigger;
+ uint8_t m_rightTrigger;
+ float m_leftThumbX;
+ float m_leftThumbY;
+ float m_rightThumbX;
+ float m_rightThumbY;
+ float m_repeat; // time since last keypress
+ bool m_fromHttpApi;
+ unsigned int m_held;
+};
+#endif
+
diff --git a/guilib/LocalizeStrings.cpp b/guilib/LocalizeStrings.cpp
new file mode 100644
index 0000000000..78f10f15f4
--- /dev/null
+++ b/guilib/LocalizeStrings.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "LocalizeStrings.h"
+#include "utils/CharsetConverter.h"
+#include "utils/log.h"
+#include "FileSystem/SpecialProtocol.h"
+#include "XMLUtils.h"
+
+CLocalizeStrings g_localizeStrings;
+CLocalizeStrings g_localizeStringsTemp;
+extern CStdString g_LoadErrorStr;
+
+CLocalizeStrings::CLocalizeStrings(void)
+{
+
+}
+
+CLocalizeStrings::~CLocalizeStrings(void)
+{
+
+}
+
+CStdString CLocalizeStrings::ToUTF8(const CStdString& strEncoding, const CStdString& str)
+{
+ if (strEncoding.IsEmpty())
+ return str;
+
+ CStdString ret;
+ g_charsetConverter.stringCharsetToUtf8(strEncoding, str, ret);
+ return ret;
+}
+
+void CLocalizeStrings::ClearSkinStrings()
+{
+ // clear the skin strings
+ Clear(31000, 31999);
+}
+
+bool CLocalizeStrings::LoadSkinStrings(const CStdString& path, const CStdString& fallbackPath)
+{
+ ClearSkinStrings();
+ // load the skin strings in.
+ CStdString encoding, error;
+ if (!LoadXML(path, encoding, error))
+ {
+ if (path == fallbackPath) // no fallback, nothing to do
+ return false;
+ }
+
+ // load the fallback
+ if (path != fallbackPath)
+ LoadXML(fallbackPath, encoding, error);
+
+ return true;
+}
+
+bool CLocalizeStrings::LoadXML(const CStdString &filename, CStdString &encoding, CStdString &error, uint32_t offset /* = 0 */)
+{
+ TiXmlDocument xmlDoc;
+ if (!xmlDoc.LoadFile(PTH_IC(filename)))
+ {
+ CLog::Log(LOGDEBUG, "unable to load %s: %s at line %d", filename.c_str(), xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
+ error.Format("Unable to load %s: %s at line %d", filename.c_str(), xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
+ return false;
+ }
+
+ XMLUtils::GetEncoding(&xmlDoc, encoding);
+
+ TiXmlElement* pRootElement = xmlDoc.RootElement();
+ if (!pRootElement || pRootElement->NoChildren() ||
+ pRootElement->ValueStr()!=CStdString("strings"))
+ {
+ CLog::Log(LOGERROR, "%s Doesn't contain <strings>", filename.c_str());
+ error.Format("%s\nDoesnt start with <strings>", filename.c_str());
+ return false;
+ }
+
+ const TiXmlElement *pChild = pRootElement->FirstChildElement("string");
+ while (pChild)
+ {
+ // Load new style language file with id as attribute
+ const char* attrId=pChild->Attribute("id");
+ if (attrId && !pChild->NoChildren())
+ {
+ int id = atoi(attrId) + offset;
+ if (m_strings.find(id) == m_strings.end())
+ m_strings[id] = ToUTF8(encoding, pChild->FirstChild()->Value());
+ }
+ pChild = pChild->NextSiblingElement("string");
+ }
+ return true;
+}
+
+bool CLocalizeStrings::Load(const CStdString& strFileName, const CStdString& strFallbackFileName)
+{
+ bool bLoadFallback = !strFileName.Equals(strFallbackFileName);
+
+ CStdString encoding, error;
+ Clear();
+
+ if (!LoadXML(strFileName, encoding, error))
+ {
+ // try loading the fallback
+ if (!bLoadFallback || !LoadXML(strFallbackFileName, encoding, error))
+ {
+ g_LoadErrorStr = error;
+ return false;
+ }
+ bLoadFallback = false;
+ }
+
+ if (bLoadFallback)
+ LoadXML(strFallbackFileName, encoding, error);
+
+ // fill in the constant strings
+ m_strings[20022] = "";
+ m_strings[20027] = ToUTF8(encoding, "°F");
+ m_strings[20028] = ToUTF8(encoding, "K");
+ m_strings[20029] = ToUTF8(encoding, "°C");
+ m_strings[20030] = ToUTF8(encoding, "°Ré");
+ m_strings[20031] = ToUTF8(encoding, "°Ra");
+ m_strings[20032] = ToUTF8(encoding, "°Rø");
+ m_strings[20033] = ToUTF8(encoding, "°De");
+ m_strings[20034] = ToUTF8(encoding, "°N");
+
+ m_strings[20200] = ToUTF8(encoding, "km/h");
+ m_strings[20201] = ToUTF8(encoding, "m/min");
+ m_strings[20202] = ToUTF8(encoding, "m/s");
+ m_strings[20203] = ToUTF8(encoding, "ft/h");
+ m_strings[20204] = ToUTF8(encoding, "ft/min");
+ m_strings[20205] = ToUTF8(encoding, "ft/s");
+ m_strings[20206] = ToUTF8(encoding, "mph");
+ m_strings[20207] = ToUTF8(encoding, "kts");
+ m_strings[20208] = ToUTF8(encoding, "Beaufort");
+ m_strings[20209] = ToUTF8(encoding, "inch/s");
+ m_strings[20210] = ToUTF8(encoding, "yard/s");
+ m_strings[20211] = ToUTF8(encoding, "Furlong/Fortnight");
+
+ return true;
+}
+
+static CStdString szEmptyString = "";
+
+const CStdString& CLocalizeStrings::Get(uint32_t dwCode) const
+{
+ ciStrings i = m_strings.find(dwCode);
+ if (i == m_strings.end())
+ {
+ return szEmptyString;
+ }
+ return i->second;
+}
+
+void CLocalizeStrings::Clear()
+{
+ m_strings.clear();
+}
+
+void CLocalizeStrings::Clear(uint32_t start, uint32_t end)
+{
+ iStrings it = m_strings.begin();
+ while (it != m_strings.end())
+ {
+ if (it->first >= start && it->first <= end)
+ m_strings.erase(it++);
+ else
+ ++it;
+ }
+}
+
+uint32_t CLocalizeStrings::LoadBlock(const CStdString &id, const CStdString &path, const CStdString &fallbackPath)
+{
+ iBlocks it = m_blocks.find(id);
+ if (it != m_blocks.end())
+ return it->second; // already loaded
+
+ // grab a new block
+ uint32_t offset = block_start + m_blocks.size()*block_size;
+ m_blocks.insert(make_pair(id, offset));
+
+ // load the strings
+ CStdString encoding, error;
+ bool success = LoadXML(path, encoding, error, offset);
+ if (!success)
+ {
+ if (path == fallbackPath) // no fallback, nothing to do
+ return 0;
+ }
+
+ // load the fallback
+ if (path != fallbackPath)
+ success |= LoadXML(fallbackPath, encoding, error, offset);
+
+ return success ? offset : 0;
+}
+
+void CLocalizeStrings::ClearBlock(const CStdString &id)
+{
+ iBlocks it = m_blocks.find(id);
+ if (it == m_blocks.end())
+ {
+ CLog::Log(LOGERROR, "%s: Trying to clear non existent block %s", __FUNCTION__, id.c_str());
+ return; // doesn't exist
+ }
+
+ // clear our block
+ Clear(it->second, it->second + block_size);
+ m_blocks.erase(it);
+}
diff --git a/guilib/LocalizeStrings.h b/guilib/LocalizeStrings.h
new file mode 100644
index 0000000000..0cb8eb731e
--- /dev/null
+++ b/guilib/LocalizeStrings.h
@@ -0,0 +1,72 @@
+/*!
+\file LocalizeStrings.h
+\brief
+*/
+
+#ifndef GUILIB_LOCALIZESTRINGS_H
+#define GUILIB_LOCALIZESTRINGS_H
+
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "StdString.h"
+
+#include <map>
+
+/*!
+ \ingroup strings
+ \brief
+ */
+class CLocalizeStrings
+{
+public:
+ CLocalizeStrings(void);
+ virtual ~CLocalizeStrings(void);
+ bool Load(const CStdString& strFileName, const CStdString& strFallbackFileName="special://xbmc/language/english/strings.xml");
+ bool LoadSkinStrings(const CStdString& path, const CStdString& fallbackPath);
+ void ClearSkinStrings();
+ const CStdString& Get(uint32_t code) const;
+ void Clear();
+ uint32_t LoadBlock(const CStdString &id, const CStdString &path, const CStdString &fallbackPath);
+ void ClearBlock(const CStdString &id);
+protected:
+ void Clear(uint32_t start, uint32_t end);
+ bool LoadXML(const CStdString &filename, CStdString &encoding, CStdString &error, uint32_t offset = 0);
+ CStdString ToUTF8(const CStdString &encoding, const CStdString &str);
+ std::map<uint32_t, CStdString> m_strings;
+ typedef std::map<uint32_t, CStdString>::const_iterator ciStrings;
+ typedef std::map<uint32_t, CStdString>::iterator iStrings;
+
+ static const uint32_t block_start = 0xf000000;
+ static const uint32_t block_size = 4096;
+ std::map<CStdString, uint32_t> m_blocks;
+ typedef std::map<CStdString, uint32_t>::iterator iBlocks;
+};
+
+/*!
+ \ingroup strings
+ \brief
+ */
+extern CLocalizeStrings g_localizeStrings;
+extern CLocalizeStrings g_localizeStringsTemp;
+#endif
diff --git a/guilib/Makefile b/guilib/Makefile
new file mode 100644
index 0000000000..3f209f9478
--- /dev/null
+++ b/guilib/Makefile
@@ -0,0 +1,87 @@
+INCLUDES=-I. -I../ -Icommon -I../xbmc -I../xbmc/cores -I../xbmc/linux -I../xbmc/utils -I/usr/include/freetype2 -I/usr/include/SDL
+
+SRCS=AnimatedGif.cpp \
+ AudioContext.cpp \
+ DirectXGraphics.cpp \
+ GraphicContext.cpp \
+ GUIAudioManager.cpp \
+ GUIBaseContainer.cpp \
+ GUIButtonControl.cpp \
+ GUIButtonScroller.cpp \
+ GUICheckMarkControl.cpp \
+ GUIControl.cpp \
+ GUIControlFactory.cpp \
+ GUIControlGroup.cpp \
+ GUIControlGroupList.cpp \
+ GUIDialog.cpp \
+ GUIEditControl.cpp \
+ GUIFadeLabelControl.cpp \
+ GUIFixedListContainer.cpp \
+ GUIFont.cpp \
+ GUIFontManager.cpp \
+ GUIFontTTF.cpp \
+ GUIImage.cpp \
+ GUIIncludes.cpp \
+ GUILabelControl.cpp \
+ GUIListContainer.cpp \
+ GUIListGroup.cpp \
+ GUIListItem.cpp \
+ GUIListItemLayout.cpp \
+ GUIMessage.cpp \
+ GUIMoverControl.cpp \
+ GUIMultiImage.cpp \
+ GUIPanelContainer.cpp \
+ GUIProgressControl.cpp \
+ GUIRadioButtonControl.cpp \
+ GUIResizeControl.cpp \
+ GUIRSSControl.cpp \
+ GUIScrollBarControl.cpp \
+ GUISelectButtonControl.cpp \
+ GUISettingsSliderControl.cpp \
+ GUISliderControl.cpp \
+ GUISpinControl.cpp \
+ GUISpinControlEx.cpp \
+ GUIStandardWindow.cpp \
+ GUITextBox.cpp \
+ GUITexture.cpp \
+ GUITextureSDL.cpp \
+ GUITextureGL.cpp \
+ GUITextureGLES.cpp \
+ GUIToggleButtonControl.cpp \
+ GUIVideoControl.cpp \
+ GUIVisualisationControl.cpp \
+ GUIWindow.cpp \
+ GUIWindowManager.cpp \
+ GUIWrappingListContainer.cpp \
+ IWindowManagerCallback.cpp \
+ Key.cpp \
+ LocalizeStrings.cpp \
+ SkinInfo.cpp \
+ TextureBundle.cpp \
+ TextureManager.cpp \
+ VisibleEffect.cpp \
+ XMLUtils.cpp \
+ GUISound.cpp \
+ GUIColorManager.cpp \
+ FrameBufferObject.cpp \
+ Shader.cpp \
+ GUIListLabel.cpp \
+ GUIBorderedImage.cpp \
+ GUITextLayout.cpp \
+ GUIMultiSelectText.cpp \
+ GUIInfoColor.cpp \
+ GUIFontTTFGL.cpp \
+ GUIFontTTFGLES.cpp \
+ Texture.cpp \
+ TextureGL.cpp \
+ GUIControlProfiler.cpp \
+
+LIB=guilib.a
+
+include ../Makefile.include
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
+
+try : try.o TextureBundle.o DirectXGraphics.o GUIFontTTF.o
+ g++ -o try try.o TextureBundle.o DirectXGraphics.o GraphicContext.o GUIIncludes.o ../xbmc/utils/CriticalSection.o ../xbmc/XBVideoConfig.o SkinInfo.o tinyXML/tinyxml.a ../xbmc/linux/CriticalSection.o GUIFontTTF.o GUIFontBase.o GUIFontManager.o GUIFont.o XMLUtils.o GUIImage.o GUIControl.o TextureManager.o GUIMessage.o ../xbmc/utils/SingleLock.o VisibleEffect.o GUIWindowManager.o AnimatedGif.o -lSDL_image -lSDL_gfx -lSDL -llzo -lfreetype
+
+
diff --git a/guilib/Resolution.h b/guilib/Resolution.h
new file mode 100644
index 0000000000..cd64fa7410
--- /dev/null
+++ b/guilib/Resolution.h
@@ -0,0 +1,99 @@
+/*
+* Copyright (C) 2005-2008 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+#pragma once
+
+#include <stdint.h>
+#include "StdString.h"
+
+enum RESOLUTION {
+ RES_INVALID = -1,
+ RES_HDTV_1080i = 0,
+ RES_HDTV_720p = 1,
+ RES_HDTV_480p_4x3 = 2,
+ RES_HDTV_480p_16x9 = 3,
+ RES_NTSC_4x3 = 4,
+ RES_NTSC_16x9 = 5,
+ RES_PAL_4x3 = 6,
+ RES_PAL_16x9 = 7,
+ RES_PAL60_4x3 = 8,
+ RES_PAL60_16x9 = 9,
+ RES_AUTORES = 10,
+ RES_WINDOW = 11,
+ RES_DESKTOP = 12,
+ RES_CUSTOM = 13
+};
+
+enum VSYNC {
+ VSYNC_DISABLED = 0,
+ VSYNC_VIDEO = 1,
+ VSYNC_ALWAYS = 2,
+ VSYNC_DRIVER = 3
+};
+
+struct OVERSCAN
+{
+ int left;
+ int top;
+ int right;
+ int bottom;
+public:
+ OVERSCAN()
+ {
+ left = top = right = bottom = 0;
+ }
+ OVERSCAN(const OVERSCAN& os)
+ {
+ left = os.left; top = os.top;
+ right = os.right; bottom = os.bottom;
+ }
+};
+
+struct RESOLUTION_INFO
+{
+ OVERSCAN Overscan;
+ bool bFullScreen;
+ int iScreen;
+ int iWidth;
+ int iHeight;
+ int iSubtitles;
+ uint32_t dwFlags;
+ float fPixelRatio;
+ float fRefreshRate;
+ CStdString strMode;
+ CStdString strOutput;
+ CStdString strId;
+ public:
+ RESOLUTION_INFO()
+ {
+ bFullScreen = false;
+ iScreen = iWidth = iHeight = iSubtitles = dwFlags = 0;
+ fPixelRatio = fRefreshRate = 0.f;
+ }
+ RESOLUTION_INFO(const RESOLUTION_INFO& res)
+ {
+ Overscan = res.Overscan; bFullScreen = res.bFullScreen;
+ iScreen = res.iScreen; iWidth = res.iWidth; iHeight = res.iHeight;
+ iSubtitles = res.iSubtitles; dwFlags = res.dwFlags;
+ fPixelRatio = res.fPixelRatio; fRefreshRate = res.fRefreshRate;
+ strMode = res.strMode; strOutput = res.strOutput; strId = res.strId;
+ }
+};
diff --git a/guilib/Shader.cpp b/guilib/Shader.cpp
new file mode 100644
index 0000000000..d492278865
--- /dev/null
+++ b/guilib/Shader.cpp
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+
+#if defined(HAS_GL) || HAS_GLES == 2
+#include "../xbmc/Settings.h"
+#include "../xbmc/FileSystem/File.h"
+#include "Shader.h"
+#include "utils/log.h"
+
+#define LOG_SIZE 1024
+
+using namespace Shaders;
+using namespace XFILE;
+using namespace std;
+
+//////////////////////////////////////////////////////////////////////
+// CShader
+//////////////////////////////////////////////////////////////////////
+bool CShader::LoadSource(const string& filename, const string& prefix)
+{
+ if(filename.empty())
+ return true;
+
+ CFileStream file;
+
+ if(!file.Open("special://xbmc/system/shaders/" + filename))
+ {
+ CLog::Log(LOGERROR, "CYUVShaderGLSL::CYUVShaderGLSL - failed to open file %s", filename.c_str());
+ return false;
+ }
+
+ getline(file, m_source, '\0');
+ m_source.insert(0, prefix);
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////
+// CGLSLVertexShader
+//////////////////////////////////////////////////////////////////////
+
+bool CGLSLVertexShader::Compile()
+{
+ GLint params[4];
+
+ Free();
+
+#ifdef HAS_GL
+ if(!GLEW_VERSION_2_0)
+ {
+ CLog::Log(LOGERROR, "GL: GLSL vertex shaders not supported");
+ return false;
+ }
+#endif
+
+ /*
+ Workaround for locale bug in nVidia's shader compiler.
+ Save the current locale, set to a neutral locale while compiling and switch back afterwards.
+ */
+ char * currentLocale = setlocale(LC_NUMERIC, NULL);
+ setlocale(LC_NUMERIC, "C");
+
+ m_vertexShader = glCreateShader(GL_VERTEX_SHADER);
+ const char *ptr = m_source.c_str();
+ glShaderSource(m_vertexShader, 1, &ptr, 0);
+ glCompileShader(m_vertexShader);
+ glGetShaderiv(m_vertexShader, GL_COMPILE_STATUS, params);
+ VerifyGLState();
+ if (params[0]!=GL_TRUE)
+ {
+ GLchar log[LOG_SIZE];
+ CLog::Log(LOGERROR, "GL: Error compiling shader");
+ glGetShaderInfoLog(m_vertexShader, LOG_SIZE, NULL, log);
+ CLog::Log(LOGERROR, "%s", log);
+ m_lastLog = log;
+ m_compiled = false;
+ }
+ else
+ {
+ GLchar log[LOG_SIZE];
+ CLog::Log(LOGDEBUG, "GL: Shader compilation log:");
+ glGetShaderInfoLog(m_vertexShader, LOG_SIZE, NULL, log);
+ CLog::Log(LOGDEBUG, "%s", log);
+ m_lastLog = log;
+ m_compiled = true;
+ }
+ setlocale(LC_NUMERIC, currentLocale);
+ return m_compiled;
+}
+
+void CGLSLVertexShader::Free()
+{
+#ifdef HAS_GL
+ if(!GLEW_VERSION_2_0)
+ return;
+#endif
+
+ if (m_vertexShader)
+ glDeleteShader(m_vertexShader);
+ m_vertexShader = 0;
+}
+
+#ifndef HAS_GLES
+
+//////////////////////////////////////////////////////////////////////
+// CARBVertexShader
+//////////////////////////////////////////////////////////////////////
+bool CARBVertexShader::Compile()
+{
+ GLint err = 0;
+
+ Free();
+
+ // Pixel shaders are not mandatory.
+ if (m_source.length()==0)
+ {
+ CLog::Log(LOGNOTICE, "GL: No vertex shader, fixed pipeline in use");
+ return true;
+ }
+
+ // Workaround for locale bug in nVidia's shader compiler.
+ // Save the current locale, set to a neutral while compiling and switch back afterwards.
+
+ char * currentLocale = setlocale(LC_NUMERIC, NULL);
+ setlocale(LC_NUMERIC, "C");
+
+ glEnable(GL_VERTEX_PROGRAM_ARB);
+ glGenProgramsARB(1, &m_vertexShader);
+ glBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_vertexShader);
+
+ glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ m_source.length(), m_source.c_str());
+
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &err);
+ if (err>0)
+ {
+ CLog::Log(LOGERROR, "GL: Error compiling ARB vertex shader");
+ m_compiled = false;
+ }
+ else
+ {
+ m_compiled = true;
+ }
+ glDisable(GL_VERTEX_PROGRAM_ARB);
+ setlocale(LC_NUMERIC, currentLocale);
+ return m_compiled;
+}
+
+void CARBVertexShader::Free()
+{
+ if (m_vertexShader)
+ glDeleteProgramsARB(1, &m_vertexShader);
+ m_vertexShader = 0;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// CGLSLPixelShader
+//////////////////////////////////////////////////////////////////////
+bool CGLSLPixelShader::Compile()
+{
+#ifdef HAS_GL
+ if(!GLEW_VERSION_2_0)
+ {
+ CLog::Log(LOGERROR, "GL: GLSL pixel shaders not supported");
+ return false;
+ }
+#endif
+
+ GLint params[4];
+
+ Free();
+
+ // Pixel shaders are not mandatory.
+ if (m_source.length()==0)
+ {
+ CLog::Log(LOGNOTICE, "GL: No pixel shader, fixed pipeline in use");
+ return true;
+ }
+
+ /*
+ Workaround for locale bug in nVidia's shader compiler.
+ Save the current locale, set to a neutral while compiling and switch back afterwards.
+ */
+ char * currentLocale = setlocale(LC_NUMERIC, NULL);
+ setlocale(LC_NUMERIC, "C");
+
+ m_pixelShader = glCreateShader(GL_FRAGMENT_SHADER);
+ const char *ptr = m_source.c_str();
+ glShaderSource(m_pixelShader, 1, &ptr, 0);
+ glCompileShader(m_pixelShader);
+ glGetShaderiv(m_pixelShader, GL_COMPILE_STATUS, params);
+ if (params[0]!=GL_TRUE)
+ {
+ GLchar log[LOG_SIZE];
+ CLog::Log(LOGERROR, "GL: Error compiling shader");
+ glGetShaderInfoLog(m_pixelShader, LOG_SIZE, NULL, log);
+ CLog::Log(LOGERROR, "%s", log);
+ m_lastLog = log;
+ m_compiled = false;
+ }
+ else
+ {
+ GLchar log[LOG_SIZE];
+ CLog::Log(LOGDEBUG, "GL: Shader compilation log:");
+ glGetShaderInfoLog(m_pixelShader, LOG_SIZE, NULL, log);
+ CLog::Log(LOGDEBUG, "%s", log);
+ m_lastLog = log;
+ m_compiled = true;
+ }
+ setlocale(LC_NUMERIC, currentLocale);
+ return m_compiled;
+}
+
+void CGLSLPixelShader::Free()
+{
+#ifdef HAS_GL
+ if(!GLEW_VERSION_2_0)
+ return;
+#endif
+ if (m_pixelShader)
+ glDeleteShader(m_pixelShader);
+ m_pixelShader = 0;
+}
+
+#ifndef HAS_GLES
+
+//////////////////////////////////////////////////////////////////////
+// CARBPixelShader
+//////////////////////////////////////////////////////////////////////
+bool CARBPixelShader::Compile()
+{
+ GLint err = 0;
+
+ Free();
+
+ // Pixel shaders are not mandatory.
+ if (m_source.length()==0)
+ {
+ CLog::Log(LOGNOTICE, "GL: No pixel shader, fixed pipeline in use");
+ return true;
+ }
+
+ // Workaround for locale bug in nVidia's shader compiler.
+ // Save the current locale, set to a neutral while compiling and switch back afterwards.
+ char currentLocale[256];
+ strncpy(currentLocale, setlocale(LC_NUMERIC, NULL), sizeof(currentLocale));
+ setlocale(LC_NUMERIC, "C");
+
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+ glGenProgramsARB(1, &m_pixelShader);
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_pixelShader);
+
+ glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ m_source.length(), m_source.c_str());
+
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &err);
+ if (err>0)
+ {
+ CLog::Log(LOGERROR, "GL: Error compiling ARB pixel shader");
+ m_compiled = false;
+ }
+ else
+ {
+ m_compiled = true;
+ }
+ glDisable(GL_FRAGMENT_PROGRAM_ARB);
+ setlocale(LC_NUMERIC, currentLocale);
+ return m_compiled;
+}
+
+void CARBPixelShader::Free()
+{
+ if (m_pixelShader)
+ glDeleteProgramsARB(1, &m_pixelShader);
+ m_pixelShader = 0;
+}
+
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// CGLSLShaderProgram
+//////////////////////////////////////////////////////////////////////
+void CGLSLShaderProgram::Free()
+{
+#ifdef HAS_GL
+ if(!GLEW_VERSION_2_0)
+ return;
+#endif
+ m_pVP->Free();
+ VerifyGLState();
+ m_pFP->Free();
+ VerifyGLState();
+ if (m_shaderProgram)
+ {
+ glDeleteProgram(m_shaderProgram);
+ }
+ m_shaderProgram = 0;
+ m_ok = false;
+ m_lastProgram = 0;
+}
+
+bool CGLSLShaderProgram::CompileAndLink()
+{
+#ifdef HAS_GL
+ // check that we support shaders
+ if(!GLEW_VERSION_2_0)
+ {
+ CLog::Log(LOGERROR, "GL: GLSL shaders not supported");
+ return false;
+ }
+#endif
+
+ GLint params[4];
+
+ // free resources
+ Free();
+
+ // compiled vertex shader
+ if (!m_pVP->Compile())
+ {
+ CLog::Log(LOGERROR, "GL: Error compiling vertex shader");
+ return false;
+ }
+
+ // compile pixel shader
+ if (!m_pFP->Compile())
+ {
+ m_pVP->Free();
+ CLog::Log(LOGERROR, "GL: Error compiling fragment shader");
+ return false;
+ }
+
+ // create program object
+ if (!(m_shaderProgram = glCreateProgram()))
+ {
+ CLog::Log(LOGERROR, "GL: Error creating shader program handle");
+ goto error;
+ }
+
+ // attach the vertex shader
+ glAttachShader(m_shaderProgram, m_pVP->Handle());
+ VerifyGLState();
+
+ // if we have a pixel shader, attach it. If not, fixed pipeline
+ // will be used.
+ if (m_pFP->Handle())
+ {
+ glAttachShader(m_shaderProgram, m_pFP->Handle());
+ VerifyGLState();
+ }
+
+ // link the program
+ glLinkProgram(m_shaderProgram);
+ glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, params);
+ if (params[0]!=GL_TRUE)
+ {
+ GLchar log[LOG_SIZE];
+ CLog::Log(LOGERROR, "GL: Error linking shader");
+ glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, NULL, log);
+ CLog::Log(LOGERROR, "%s", log);
+ goto error;
+ }
+ VerifyGLState();
+
+ // validate the program
+ glValidateProgram(m_shaderProgram);
+ glGetProgramiv(m_shaderProgram, GL_VALIDATE_STATUS, params);
+ if (params[0]!=GL_TRUE)
+ {
+ GLchar log[LOG_SIZE];
+ CLog::Log(LOGERROR, "GL: Error validating shader");
+ glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, NULL, log);
+ CLog::Log(LOGERROR, "%s", log);
+ goto error;
+ }
+ VerifyGLState();
+
+ m_ok = true;
+ OnCompiledAndLinked();
+ VerifyGLState();
+ return true;
+
+ error:
+ m_ok = false;
+ Free();
+ return false;
+}
+
+bool CGLSLShaderProgram::Enable()
+{
+#ifdef HAS_GL
+ if(!GLEW_VERSION_2_0)
+ return false;
+#endif
+
+ if (OK())
+ {
+ glUseProgram(m_shaderProgram);
+ if (OnEnabled())
+ {
+ VerifyGLState();
+ return true;
+ }
+ else
+ {
+ glUseProgram(0);
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+void CGLSLShaderProgram::Disable()
+{
+#ifdef HAS_GL
+ if(!GLEW_VERSION_2_0)
+ return;
+#endif
+
+ if (OK())
+ {
+ glUseProgram(0);
+ OnDisabled();
+ }
+}
+
+#ifndef HAS_GLES
+
+//////////////////////////////////////////////////////////////////////
+// CARBShaderProgram
+//////////////////////////////////////////////////////////////////////
+void CARBShaderProgram::Free()
+{
+ m_pVP->Free();
+ VerifyGLState();
+ m_pFP->Free();
+ VerifyGLState();
+ m_ok = false;
+}
+
+bool CARBShaderProgram::CompileAndLink()
+{
+ // free resources
+ Free();
+
+ // compiled vertex shader
+ if (!m_pVP->Compile())
+ {
+ CLog::Log(LOGERROR, "GL: Error compiling vertex shader");
+ goto error;
+ }
+
+ // compile pixel shader
+ if (!m_pFP->Compile())
+ {
+ m_pVP->Free();
+ CLog::Log(LOGERROR, "GL: Error compiling fragment shader");
+ goto error;
+ }
+
+ m_ok = true;
+ OnCompiledAndLinked();
+ VerifyGLState();
+ return true;
+
+ error:
+ m_ok = false;
+ Free();
+ return false;
+}
+
+bool CARBShaderProgram::Enable()
+{
+ if (OK())
+ {
+ if (m_pFP->OK())
+ {
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_pFP->Handle());
+ }
+ if (m_pVP->OK())
+ {
+ glEnable(GL_VERTEX_PROGRAM_ARB);
+ glBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_pVP->Handle());
+ }
+ if (OnEnabled())
+ {
+ VerifyGLState();
+ return true;
+ }
+ else
+ {
+ glDisable(GL_FRAGMENT_PROGRAM_ARB);
+ glDisable(GL_VERTEX_PROGRAM_ARB);
+ return false;
+ }
+ }
+ return false;
+}
+
+void CARBShaderProgram::Disable()
+{
+ if (OK())
+ {
+ glDisable(GL_FRAGMENT_PROGRAM_ARB);
+ glDisable(GL_VERTEX_PROGRAM_ARB);
+ OnDisabled();
+ }
+}
+
+#endif
+
+#endif
diff --git a/guilib/Shader.h b/guilib/Shader.h
new file mode 100644
index 0000000000..b9d6775dc8
--- /dev/null
+++ b/guilib/Shader.h
@@ -0,0 +1,263 @@
+#ifndef __SHADER_H__
+#define __SHADER_H__
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+
+#include <vector>
+#include <string>
+
+#if defined(HAS_GL) || defined(HAS_GLES)
+
+namespace Shaders {
+
+ using namespace std;
+
+ //////////////////////////////////////////////////////////////////////
+ // CShader - base class
+ //////////////////////////////////////////////////////////////////////
+ class CShader
+ {
+ public:
+ CShader() { m_compiled = false; }
+ virtual ~CShader() { }
+ virtual bool Compile() = 0;
+ virtual void Free() = 0;
+ virtual GLuint Handle() = 0;
+ virtual void SetSource(const string& src) { m_source = src; }
+ virtual bool LoadSource(const string& filename, const string& prefix = "");
+ bool OK() { return m_compiled; }
+
+ protected:
+ string m_source;
+ string m_lastLog;
+ vector<string> m_attr;
+ bool m_compiled;
+
+ };
+
+
+ //////////////////////////////////////////////////////////////////////
+ // CVertexShader - vertex shader class
+ //////////////////////////////////////////////////////////////////////
+ class CVertexShader : public CShader
+ {
+ public:
+ CVertexShader() { m_vertexShader = 0; }
+ virtual ~CVertexShader() { Free(); }
+ virtual void Free() {}
+ virtual GLuint Handle() { return m_vertexShader; }
+
+ protected:
+ GLuint m_vertexShader;
+ };
+
+ class CGLSLVertexShader : public CVertexShader
+ {
+ public:
+ virtual void Free();
+ virtual bool Compile();
+ };
+
+#ifndef HAS_GLES
+ class CARBVertexShader : public CVertexShader
+ {
+ public:
+ virtual void Free();
+ virtual bool Compile();
+ };
+#endif
+
+
+ //////////////////////////////////////////////////////////////////////
+ // CPixelShader - abstract pixel shader class
+ //////////////////////////////////////////////////////////////////////
+ class CPixelShader : public CShader
+ {
+ public:
+ CPixelShader() { m_pixelShader = 0; }
+ virtual ~CPixelShader() { Free(); }
+ virtual void Free() {}
+ virtual GLuint Handle() { return m_pixelShader; }
+
+ protected:
+ GLuint m_pixelShader;
+ };
+
+
+ class CGLSLPixelShader : public CPixelShader
+ {
+ public:
+ virtual void Free();
+ virtual bool Compile();
+ };
+
+#ifndef HAS_GLES
+ class CARBPixelShader : public CPixelShader
+ {
+ public:
+ virtual void Free();
+ virtual bool Compile();
+ };
+#endif
+
+ //////////////////////////////////////////////////////////////////////
+ // CShaderProgram - the complete shader consisting of both the vertex
+ // and pixel programs. (abstract)
+ //////////////////////////////////////////////////////////////////////
+ class CShaderProgram
+ {
+ public:
+ CShaderProgram()
+ {
+ m_ok = false;
+ m_shaderProgram = 0;
+ m_pFP = NULL;
+ m_pVP = NULL;
+ }
+
+ virtual ~CShaderProgram()
+ {
+ Free();
+ delete m_pFP;
+ delete m_pVP;
+ }
+
+ // enable the shader
+ virtual bool Enable() = 0;
+
+ // disable the shader
+ virtual void Disable() = 0;
+
+ // returns true if shader is compiled and linked
+ bool OK() { return m_ok; }
+
+ // free resources
+ virtual void Free() {}
+
+ // return the vertex shader object
+ CVertexShader* VertexShader() { return m_pVP; }
+
+ // return the pixel shader object
+ CPixelShader* PixelShader() { return m_pFP; }
+
+ // compile and link the shaders
+ virtual bool CompileAndLink() = 0;
+
+ // override to to perform custom tasks on successfull compilation
+ // and linkage. E.g. obtaining handles to shader attributes.
+ virtual void OnCompiledAndLinked() {}
+
+ // override to to perform custom tasks before shader is enabled
+ // and after it is disabled. Return false in OnDisabled() to
+ // disable shader.
+ // E.g. setting attributes, disabling texture unites, etc
+ virtual bool OnEnabled() { return true; }
+ virtual void OnDisabled() { }
+
+ virtual GLuint ProgramHandle() { return m_shaderProgram; }
+
+ protected:
+ CVertexShader* m_pVP;
+ CPixelShader* m_pFP;
+ GLuint m_shaderProgram;
+ bool m_ok;
+ };
+
+
+ class CGLSLShaderProgram
+ : virtual public CShaderProgram
+ {
+ public:
+ CGLSLShaderProgram()
+ {
+ m_pFP = new CGLSLPixelShader();
+ m_pVP = new CGLSLVertexShader();
+ }
+ CGLSLShaderProgram(const std::string& vert
+ , const std::string& frag)
+ {
+ m_pFP = new CGLSLPixelShader();
+ m_pFP->LoadSource(vert);
+ m_pVP = new CGLSLVertexShader();
+ m_pVP->LoadSource(vert);
+ }
+
+ // enable the shader
+ virtual bool Enable();
+
+ // disable the shader
+ virtual void Disable();
+
+ // free resources
+ virtual void Free();
+
+ // compile and link the shaders
+ virtual bool CompileAndLink();
+
+ protected:
+ GLint m_lastProgram;
+ };
+
+
+#ifndef HAS_GLES
+ class CARBShaderProgram
+ : virtual public CShaderProgram
+ {
+ public:
+ CARBShaderProgram()
+ {
+ m_pFP = new CARBPixelShader();
+ m_pVP = new CARBVertexShader();
+ }
+ CARBShaderProgram(const std::string& vert
+ , const std::string& frag)
+ {
+ m_pFP = new CARBPixelShader();
+ m_pFP->LoadSource(vert);
+ m_pVP = new CARBVertexShader();
+ m_pVP->LoadSource(vert);
+ }
+
+ // enable the shader
+ virtual bool Enable();
+
+ // disable the shader
+ virtual void Disable();
+
+ // free resources
+ virtual void Free();
+
+ // compile and link the shaders
+ virtual bool CompileAndLink();
+
+ protected:
+
+ };
+#endif
+
+} // close namespace
+
+#endif
+
+#endif //__SHADER_H__
diff --git a/guilib/SkinInfo.cpp b/guilib/SkinInfo.cpp
new file mode 100644
index 0000000000..8b33ac0159
--- /dev/null
+++ b/guilib/SkinInfo.cpp
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "SkinInfo.h"
+#include "GUIWindowManager.h"
+#include "GUISettings.h"
+#include "FileSystem/File.h"
+#include "FileSystem/SpecialProtocol.h"
+#include "Key.h"
+#include "Util.h"
+#include "Settings.h"
+#include "StringUtils.h"
+#include "utils/log.h"
+#include "tinyXML/tinyxml.h"
+
+using namespace std;
+using namespace XFILE;
+
+#define SKIN_MIN_VERSION 2.1f
+
+CSkinInfo g_SkinInfo; // global
+
+CSkinInfo::CSkinInfo()
+{
+ m_DefaultResolution = RES_INVALID;
+ m_DefaultResolutionWide = RES_INVALID;
+ m_strBaseDir = "";
+ m_iNumCreditLines = 0;
+ m_effectsSlowDown = 1.0;
+ m_onlyAnimateToHome = true;
+ m_Version = 1.0;
+ m_skinzoom = 1.0f;
+}
+
+CSkinInfo::~CSkinInfo()
+{}
+
+void CSkinInfo::Load(const CStdString& strSkinDir)
+{
+ m_strBaseDir = strSkinDir;
+ m_DefaultResolution = RES_INVALID; // set to INVALID to denote that there is no default res here
+ m_DefaultResolutionWide = RES_INVALID;
+ m_effectsSlowDown = 1.0;
+ // Load from skin.xml
+ TiXmlDocument xmlDoc;
+ CStdString strFile = m_strBaseDir + "\\skin.xml";
+ if (xmlDoc.LoadFile(strFile))
+ { // ok - get the default skin folder out of it...
+ TiXmlElement* pRootElement = xmlDoc.RootElement();
+ CStdString strValue = pRootElement->Value();
+ if (strValue != "skin")
+ {
+ CLog::Log(LOGERROR, "file :%s doesnt contain <skin>", strFile.c_str());
+ }
+ else
+ { // get the default resolution
+ TiXmlNode *pChild = pRootElement->FirstChild("defaultresolution");
+ if (pChild)
+ { // found the defaultresolution tag
+ CStdString strDefaultDir = pChild->FirstChild()->Value();
+ strDefaultDir = strDefaultDir.ToLower();
+ if (strDefaultDir == "pal") m_DefaultResolution = RES_PAL_4x3;
+ else if (strDefaultDir == "pal16x9") m_DefaultResolution = RES_PAL_16x9;
+ else if (strDefaultDir == "ntsc") m_DefaultResolution = RES_NTSC_4x3;
+ else if (strDefaultDir == "ntsc16x9") m_DefaultResolution = RES_NTSC_16x9;
+ else if (strDefaultDir == "720p") m_DefaultResolution = RES_HDTV_720p;
+ else if (strDefaultDir == "1080i") m_DefaultResolution = RES_HDTV_1080i;
+ }
+ CLog::Log(LOGINFO, "Default 4:3 resolution directory is %s", CUtil::AddFileToFolder(m_strBaseDir, GetDirFromRes(m_DefaultResolution)).c_str());
+
+ pChild = pRootElement->FirstChild("defaultresolutionwide");
+ if (pChild && pChild->FirstChild())
+ { // found the defaultresolution tag
+ CStdString strDefaultDir = pChild->FirstChild()->Value();
+ strDefaultDir = strDefaultDir.ToLower();
+ if (strDefaultDir == "pal") m_DefaultResolutionWide = RES_PAL_4x3;
+ else if (strDefaultDir == "pal16x9") m_DefaultResolutionWide = RES_PAL_16x9;
+ else if (strDefaultDir == "ntsc") m_DefaultResolutionWide = RES_NTSC_4x3;
+ else if (strDefaultDir == "ntsc16x9") m_DefaultResolutionWide = RES_NTSC_16x9;
+ else if (strDefaultDir == "720p") m_DefaultResolutionWide = RES_HDTV_720p;
+ else if (strDefaultDir == "1080i") m_DefaultResolutionWide = RES_HDTV_1080i;
+ }
+ else
+ m_DefaultResolutionWide = m_DefaultResolution; // default to same as 4:3
+ CLog::Log(LOGINFO, "Default 16:9 resolution directory is %s", CUtil::AddFileToFolder(m_strBaseDir, GetDirFromRes(m_DefaultResolutionWide)).c_str());
+
+ // get the version
+ pChild = pRootElement->FirstChild("version");
+ if (pChild && pChild->FirstChild())
+ {
+ m_Version = StringUtils::GetFloat(pChild->FirstChild()->Value());
+ CLog::Log(LOGINFO, "Skin version is: %s", pChild->FirstChild()->Value());
+ }
+
+ // get the effects slowdown parameter
+ pChild = pRootElement->FirstChild("effectslowdown");
+ if (pChild && pChild->FirstChild())
+ m_effectsSlowDown = StringUtils::GetFloat(pChild->FirstChild()->Value());
+
+ // now load the credits information
+ pChild = pRootElement->FirstChild("credits");
+ if (pChild)
+ { // ok, run through the credits
+ TiXmlNode *pGrandChild = pChild->FirstChild("skinname");
+ if (pGrandChild && pGrandChild->FirstChild())
+ {
+ CStdString strName = pGrandChild->FirstChild()->Value();
+#ifndef _LINUX
+ swprintf(credits[0], L"%S Skin", strName.Left(44).c_str());
+#else
+ swprintf(credits[0], CREDIT_LINE_LENGTH - 1, L"%s Skin", strName.Left(44).c_str());
+#endif
+ }
+ pGrandChild = pChild->FirstChild("name");
+ m_iNumCreditLines = 1;
+ while (pGrandChild && pGrandChild->FirstChild() && m_iNumCreditLines < 6)
+ {
+ CStdString strName = pGrandChild->FirstChild()->Value();
+#ifndef _LINUX
+ swprintf(credits[m_iNumCreditLines], L"%S", strName.Left(49).c_str());
+#else
+ swprintf(credits[m_iNumCreditLines], CREDIT_LINE_LENGTH - 1, L"%s", strName.Left(49).c_str());
+#endif
+ m_iNumCreditLines++;
+ pGrandChild = pGrandChild->NextSibling("name");
+ }
+ }
+
+ // get the skin zoom parameter. it's how much skin should be enlarged to get rid of overscan
+ pChild = pRootElement->FirstChild("zoom");
+ if (pChild && pChild->FirstChild())
+ m_skinzoom = StringUtils::GetFloat(pChild->FirstChild()->Value());
+ else
+ m_skinzoom = 1.0f;
+
+ // now load the startupwindow information
+ LoadStartupWindows(pRootElement->FirstChildElement("startupwindows"));
+ }
+ }
+ // Load the skin includes
+ LoadIncludes();
+}
+
+bool CSkinInfo::Check(const CStdString& strSkinDir)
+{
+ bool bVersionOK = false;
+ // Load from skin.xml
+ TiXmlDocument xmlDoc;
+ CStdString strFile = CUtil::AddFileToFolder(strSkinDir, "skin.xml");
+ CStdString strGoodPath = strSkinDir;
+ if (xmlDoc.LoadFile(strFile))
+ { // ok - get the default res folder out of it...
+ TiXmlElement* pRootElement = xmlDoc.RootElement();
+ CStdString strValue = pRootElement->Value();
+ if (strValue == "skin")
+ { // get the default resolution
+ TiXmlNode *pChild = pRootElement->FirstChild("defaultresolution");
+ if (pChild)
+ { // found the defaultresolution tag
+#ifndef _LINUX
+ strGoodPath += "\\";
+#else
+ strGoodPath += "/";
+#endif
+ CStdString resolution = pChild->FirstChild()->Value();
+ if (resolution == "pal") resolution = "PAL";
+ else if (resolution == "pal16x9") resolution = "PAL16x9";
+ else if (resolution == "ntsc") resolution = "NTSC";
+ else if (resolution == "ntsc16x9") resolution = "NTSC16x9";
+ strGoodPath = CUtil::AddFileToFolder(strGoodPath, resolution);
+ }
+ // get the version
+ pChild = pRootElement->FirstChild("version");
+ if (pChild)
+ {
+ float parsedVersion;
+ parsedVersion = StringUtils::GetFloat(pChild->FirstChild()->Value());
+ bVersionOK = parsedVersion >= SKIN_MIN_VERSION;
+
+ CLog::Log(LOGINFO, "Skin version is: %s (%f)", pChild->FirstChild()->Value(), parsedVersion);
+ }
+ }
+ }
+ // Check to see if we have a good path
+ CStdString strFontXML = CUtil::AddFileToFolder(strGoodPath, "Font.xml");
+ CStdString strHomeXML = CUtil::AddFileToFolder(strGoodPath, "Home.xml");
+ if ( CFile::Exists(strFontXML) &&
+ CFile::Exists(strHomeXML) && bVersionOK )
+ {
+ return true;
+ }
+ return false;
+}
+
+CStdString CSkinInfo::GetSkinPath(const CStdString& strFile, RESOLUTION *res, const CStdString& strBaseDir /* = "" */)
+{
+ CStdString strPathToUse = m_strBaseDir;
+ if (!strBaseDir.IsEmpty())
+ strPathToUse = strBaseDir;
+ // first try and load from the current resolution's directory
+ int height=0;
+ *res = g_graphicsContext.GetVideoResolution();
+ if (*res >= RES_WINDOW)
+ {
+ height = g_settings.m_ResInfo[*res].iHeight;
+ if (height>=1080 && (g_settings.m_ResInfo[*res].dwFlags & D3DPRESENTFLAG_WIDESCREEN))
+ {
+ *res = RES_HDTV_1080i;
+ }
+ else if (height>=720 && (g_settings.m_ResInfo[*res].dwFlags & D3DPRESENTFLAG_WIDESCREEN))
+ {
+ *res = RES_HDTV_720p;
+ }
+ else if (g_settings.m_ResInfo[*res].dwFlags & D3DPRESENTFLAG_WIDESCREEN)
+ {
+ *res = RES_PAL_16x9;
+ }
+ else
+ {
+ *res = RES_PAL_4x3;
+ }
+ }
+ CStdString strPath = CUtil::AddFileToFolder(strPathToUse, GetDirFromRes(*res));
+ strPath = CUtil::AddFileToFolder(strPath, strFile);
+ if (CFile::Exists(strPath))
+ return strPath;
+ // if we're in 1080i mode, try 720p next
+ if (*res == RES_HDTV_1080i)
+ {
+ *res = RES_HDTV_720p;
+ strPath = CUtil::AddFileToFolder(strPathToUse, GetDirFromRes(*res));
+ strPath = CUtil::AddFileToFolder(strPath, strFile);
+ if (CFile::Exists(strPath))
+ return strPath;
+ }
+ // that failed - drop to the default widescreen resolution if where in a widemode
+ if (*res == RES_PAL_16x9 || *res == RES_NTSC_16x9 || *res == RES_HDTV_480p_16x9 || *res == RES_HDTV_720p)
+ {
+ *res = m_DefaultResolutionWide;
+ strPath = CUtil::AddFileToFolder(strPathToUse, GetDirFromRes(*res));
+ strPath = CUtil::AddFileToFolder(strPath, strFile);
+ if (CFile::Exists(strPath))
+ return strPath;
+ }
+ // that failed - drop to the default resolution
+ *res = m_DefaultResolution;
+ strPath = CUtil::AddFileToFolder(strPathToUse, GetDirFromRes(*res));
+ strPath = CUtil::AddFileToFolder(strPath, strFile);
+ // check if we don't have any subdirectories
+ if (*res == RES_INVALID) *res = RES_PAL_4x3;
+ return strPath;
+}
+
+bool CSkinInfo::HasSkinFile(const CStdString &strFile)
+{
+ RESOLUTION res = RES_INVALID;
+ return CFile::Exists(GetSkinPath(strFile, &res));
+}
+
+CStdString CSkinInfo::GetDirFromRes(RESOLUTION res)
+{
+ CStdString strRes;
+ switch (res)
+ {
+ case RES_PAL_4x3:
+ strRes = "PAL";
+ break;
+ case RES_PAL_16x9:
+ strRes = "PAL16x9";
+ break;
+ case RES_NTSC_4x3:
+ case RES_HDTV_480p_4x3:
+ strRes = "NTSC";
+ break;
+ case RES_NTSC_16x9:
+ case RES_HDTV_480p_16x9:
+ strRes = "ntsc16x9";
+ break;
+ case RES_HDTV_720p:
+ strRes = "720p";
+ break;
+ case RES_HDTV_1080i:
+ strRes = "1080i";
+ break;
+ case RES_INVALID:
+ default:
+ strRes = "";
+ break;
+ }
+ return strRes;
+}
+
+CStdString CSkinInfo::GetBaseDir()
+{
+ return m_strBaseDir;
+}
+
+wchar_t* CSkinInfo::GetCreditsLine(int i)
+{
+ if (i < m_iNumCreditLines)
+ return credits[i];
+ else
+ return NULL;
+}
+
+double CSkinInfo::GetMinVersion()
+{
+ return SKIN_MIN_VERSION;
+}
+
+void CSkinInfo::LoadIncludes()
+{
+ RESOLUTION res;
+ CStdString includesPath = PTH_IC(GetSkinPath("includes.xml", &res));
+ CLog::Log(LOGINFO, "Loading skin includes from %s", includesPath.c_str());
+ m_includes.ClearIncludes();
+ m_includes.LoadIncludes(includesPath);
+}
+
+void CSkinInfo::ResolveIncludes(TiXmlElement *node, const CStdString &type)
+{
+ m_includes.ResolveIncludes(node, type);
+}
+
+bool CSkinInfo::ResolveConstant(const CStdString &constant, float &value)
+{
+ return m_includes.ResolveConstant(constant, value);
+}
+
+bool CSkinInfo::ResolveConstant(const CStdString &constant, DWORD &value)
+{
+ float fValue;
+ if (m_includes.ResolveConstant(constant, fValue))
+ {
+ value = (DWORD)fValue;
+ return true;
+ }
+ return false;
+}
+
+int CSkinInfo::GetStartWindow()
+{
+ int windowID = g_guiSettings.GetInt("lookandfeel.startupwindow");
+ assert(m_startupWindows.size());
+ for (vector<CStartupWindow>::iterator it = m_startupWindows.begin(); it != m_startupWindows.end(); it++)
+ {
+ if (windowID == (*it).m_id)
+ return windowID;
+ }
+ // return our first one
+ return m_startupWindows[0].m_id;
+}
+
+bool CSkinInfo::LoadStartupWindows(const TiXmlElement *startup)
+{
+ m_startupWindows.clear();
+ if (startup)
+ { // yay, run through and grab the startup windows
+ const TiXmlElement *window = startup->FirstChildElement("window");
+ while (window && window->FirstChild())
+ {
+ int id;
+ window->Attribute("id", &id);
+ CStdString name = window->FirstChild()->Value();
+ m_startupWindows.push_back(CStartupWindow(id + WINDOW_HOME, name));
+ window = window->NextSiblingElement("window");
+ }
+ }
+
+ // ok, now see if we have any startup windows
+ if (!m_startupWindows.size())
+ { // nope - add the default ones
+ m_startupWindows.push_back(CStartupWindow(WINDOW_HOME, "513"));
+ m_startupWindows.push_back(CStartupWindow(WINDOW_PROGRAMS, "0"));
+ m_startupWindows.push_back(CStartupWindow(WINDOW_PICTURES, "1"));
+ m_startupWindows.push_back(CStartupWindow(WINDOW_MUSIC, "2"));
+ m_startupWindows.push_back(CStartupWindow(WINDOW_VIDEOS, "3"));
+ m_startupWindows.push_back(CStartupWindow(WINDOW_FILES, "7"));
+ m_startupWindows.push_back(CStartupWindow(WINDOW_SETTINGS_MENU, "5"));
+ m_startupWindows.push_back(CStartupWindow(WINDOW_SCRIPTS, "247"));
+ m_onlyAnimateToHome = true;
+ }
+ else
+ m_onlyAnimateToHome = false;
+ return true;
+}
+void CSkinInfo::SetDefaults()
+{
+ m_DefaultResolution = RES_PAL_4x3;
+ m_DefaultResolutionWide = RES_PAL_16x9;
+}
diff --git a/guilib/SkinInfo.h b/guilib/SkinInfo.h
new file mode 100644
index 0000000000..38dec2bccf
--- /dev/null
+++ b/guilib/SkinInfo.h
@@ -0,0 +1,95 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "GraphicContext.h" // needed for the RESOLUTION members
+#include "GUIIncludes.h" // needed for the GUIInclude member
+
+#define CREDIT_LINE_LENGTH 50
+
+class CSkinInfo
+{
+public:
+ class CStartupWindow
+ {
+ public:
+ CStartupWindow(int id, const CStdString &name)
+ {
+ m_id = id; m_name = name;
+ };
+ int m_id;
+ CStdString m_name;
+ };
+
+ CSkinInfo();
+ ~CSkinInfo();
+
+ void Load(const CStdString& strSkinDir); // load the skin.xml file if it exists, and configure our directories etc.
+ bool Check(const CStdString& strSkinDir); // checks if everything is present and accounted for without loading the skin
+
+ bool HasSkinFile(const CStdString &strFile);
+ CStdString GetSkinPath(const CStdString& strFile, RESOLUTION *res, const CStdString& strBaseDir=""); // retrieve the best skin file for the resolution we are in - res will be made the resolution we are loading from
+ wchar_t* GetCreditsLine(int i);
+
+ CStdString GetDirFromRes(RESOLUTION res);
+ CStdString GetBaseDir();
+ double GetMinVersion();
+ double GetVersion(){ return m_Version;};
+ int GetStartWindow();
+
+ void ResolveIncludes(TiXmlElement *node, const CStdString &type = "");
+ bool ResolveConstant(const CStdString &constant, float &value);
+ bool ResolveConstant(const CStdString &constant, DWORD &value);
+
+ double GetEffectsSlowdown() const { return m_effectsSlowDown; };
+
+ const std::vector<CStartupWindow> &GetStartupWindows() { return m_startupWindows; };
+
+ bool OnlyAnimateToHome() { return m_onlyAnimateToHome; };
+
+ inline float GetSkinZoom() { return m_skinzoom; };
+
+ inline const RESOLUTION& GetDefaultWideResolution() { return m_DefaultResolutionWide; };
+ inline const RESOLUTION& GetDefaultResolution() { return m_DefaultResolution; };
+
+ void SetDefaults();
+protected:
+ void LoadIncludes();
+ bool LoadStartupWindows(const TiXmlElement *startup);
+
+ wchar_t credits[6][CREDIT_LINE_LENGTH]; // credits info
+ int m_iNumCreditLines; // number of credit lines
+ RESOLUTION m_DefaultResolution; // default resolution for the skin in 4:3 modes
+ RESOLUTION m_DefaultResolutionWide; // default resolution for the skin in 16:9 modes
+ CStdString m_strBaseDir;
+ double m_Version;
+
+ double m_effectsSlowDown;
+ CGUIIncludes m_includes;
+
+ std::vector<CStartupWindow> m_startupWindows;
+ bool m_onlyAnimateToHome;
+
+ float m_skinzoom;
+};
+
+extern CSkinInfo g_SkinInfo;
diff --git a/guilib/StdString.h b/guilib/StdString.h
new file mode 100644
index 0000000000..ab64f7a6ea
--- /dev/null
+++ b/guilib/StdString.h
@@ -0,0 +1,4335 @@
+#pragma once
+#include <string>
+#include <stdint.h>
+#include <vector>
+#if !defined(_LINUX)
+#include "win32/PlatformDefs.h" // for va_copy
+#endif
+
+// =============================================================================
+// FILE: StdString.h
+// AUTHOR: Joe O'Leary (with outside help noted in comments)
+//
+// If you find any bugs in this code, please let me know:
+//
+// jmoleary@earthlink.net
+// http://www.joeo.net/stdstring.htm (a bit outdated)
+//
+// The latest version of this code should always be available at the
+// following link:
+//
+// http://www.joeo.net/code/StdString.zip (Dec 6, 2003)
+//
+//
+// REMARKS:
+// This header file declares the CStdStr template. This template derives
+// the Standard C++ Library basic_string<> template and add to it the
+// the following conveniences:
+// - The full MFC CString set of functions (including implicit cast)
+// - writing to/reading from COM IStream interfaces
+// - Functional objects for use in STL algorithms
+//
+// From this template, we intstantiate two classes: CStdStringA and
+// CStdStringW. The name "CStdString" is just a #define of one of these,
+// based upone the UNICODE macro setting
+//
+// This header also declares our own version of the MFC/ATL UNICODE-MBCS
+// conversion macros. Our version looks exactly like the Microsoft's to
+// facilitate portability.
+//
+// NOTE:
+// If you you use this in an MFC or ATL build, you should include either
+// afx.h or atlbase.h first, as appropriate.
+//
+// PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:
+//
+// Several people have helped me iron out problems and othewise improve
+// this class. OK, this is a long list but in my own defense, this code
+// has undergone two major rewrites. Many of the improvements became
+// necessary after I rewrote the code as a template. Others helped me
+// improve the CString facade.
+//
+// Anyway, these people are (in chronological order):
+//
+// - Pete the Plumber (???)
+// - Julian Selman
+// - Chris (of Melbsys)
+// - Dave Plummer
+// - John C Sipos
+// - Chris Sells
+// - Nigel Nunn
+// - Fan Xia
+// - Matthew Williams
+// - Carl Engman
+// - Mark Zeren
+// - Craig Watson
+// - Rich Zuris
+// - Karim Ratib
+// - Chris Conti
+// - Baptiste Lepilleur
+// - Greg Pickles
+// - Jim Cline
+// - Jeff Kohn
+// - Todd Heckel
+// - Ullrich Poll�hne
+// - Joe Vitaterna
+// - Joe Woodbury
+// - Aaron (no last name)
+// - Joldakowski (???)
+// - Scott Hathaway
+// - Eric Nitzche
+// - Pablo Presedo
+// - Farrokh Nejadlotfi
+// - Jason Mills
+// - Igor Kholodov
+// - Mike Crusader
+// - John James
+// - Wang Haifeng
+// - Tim Dowty
+// - Arnt Witteveen
+// - Glen Maynard
+// - Paul DeMarco
+// - Bagira (full name?)
+// - Ronny Schulz
+// - Jakko Van Hunen
+// - Charles Godwin
+// - Henk Demper
+// - Greg Marr
+// - Bill Carducci
+// - Brian Groose
+// - MKingman
+// - Don Beusee
+//
+// REVISION HISTORY
+//
+// 2005-JAN-10 - Thanks to Don Beusee for pointing out the danger in mapping
+// length-checked formatting functions to non-length-checked
+// CRT equivalents. Also thanks to him for motivating me to
+// optimize my implementation of Replace()
+//
+// 2004-APR-22 - A big, big thank you to "MKingman" (whoever you are) for
+// finally spotting a silly little error in StdCodeCvt that
+// has been causing me (and users of CStdString) problems for
+// years in some relatively rare conversions. I had reversed
+// two length arguments.
+//
+// 2003-NOV-24 - Thanks to a bunch of people for helping me clean up many
+// compiler warnings (and yes, even a couple of actual compiler
+// errors). These include Henk Demper for figuring out how
+// to make the Intellisense work on with CStdString on VC6,
+// something I was never able to do. Greg Marr pointed out
+// a compiler warning about an unreferenced symbol and a
+// problem with my version of Load in MFC builds. Bill
+// Carducci took a lot of time with me to help me figure out
+// why some implementations of the Standard C++ Library were
+// returning error codes for apparently successful conversions
+// between ASCII and UNICODE. Finally thanks to Brian Groose
+// for helping me fix compiler signed unsigned warnings in
+// several functions.
+//
+// 2003-JUL-10 - Thanks to Charles Godwin for making me realize my 'FmtArg'
+// fixes had inadvertently broken the DLL-export code (which is
+// normally commented out. I had to move it up higher. Also
+// this helped me catch a bug in ssicoll that would prevent
+// compilation, otherwise.
+//
+// 2003-MAR-14 - Thanks to Jakko Van Hunen for pointing out a copy-and-paste
+// bug in one of the overloads of FmtArg.
+//
+// 2003-MAR-10 - Thanks to Ronny Schulz for (twice!) sending me some changes
+// to help CStdString build on SGI and for pointing out an
+// error in placement of my preprocessor macros for ssfmtmsg.
+//
+// 2002-NOV-26 - Thanks to Bagira for pointing out that my implementation of
+// SpanExcluding was not properly handling the case in which
+// the string did NOT contain any of the given characters
+//
+// 2002-OCT-21 - Many thanks to Paul DeMarco who was invaluable in helping me
+// get this code working with Borland's free compiler as well
+// as the Dev-C++ compiler (available free at SourceForge).
+//
+// 2002-SEP-13 - Thanks to Glen Maynard who helped me get rid of some loud
+// but harmless warnings that were showing up on g++. Glen
+// also pointed out that some pre-declarations of FmtArg<>
+// specializations were unnecessary (and no good on G++)
+//
+// 2002-JUN-26 - Thanks to Arnt Witteveen for pointing out that I was using
+// static_cast<> in a place in which I should have been using
+// reinterpret_cast<> (the ctor for unsigned char strings).
+// That's what happens when I don't unit-test properly!
+// Arnt also noticed that CString was silently correcting the
+// 'nCount' argument to Left() and Right() where CStdString was
+// not (and crashing if it was bad). That is also now fixed!
+//
+// 2002-FEB-25 - Thanks to Tim Dowty for pointing out (and giving me the fix
+// for) a conversion problem with non-ASCII MBCS characters.
+// CStdString is now used in my favorite commercial MP3 player!
+//
+// 2001-DEC-06 - Thanks to Wang Haifeng for spotting a problem in one of the
+// assignment operators (for _bstr_t) that would cause compiler
+// errors when refcounting protection was turned off.
+//
+// 2001-NOV-27 - Remove calls to operator!= which involve reverse_iterators
+// due to a conflict with the rel_ops operator!=. Thanks to
+// John James for pointing this out.
+//
+// 2001-OCT-29 - Added a minor range checking fix for the Mid function to
+// make it as forgiving as CString's version is. Thanks to
+// Igor Kholodov for noticing this.
+// - Added a specialization of std::swap for CStdString. Thanks
+// to Mike Crusader for suggesting this! It's commented out
+// because you're not supposed to inject your own code into the
+// 'std' namespace. But if you don't care about that, it's
+// there if you want it
+// - Thanks to Jason Mills for catching a case where CString was
+// more forgiving in the Delete() function than I was.
+//
+// 2001-JUN-06 - I was violating the Standard name lookup rules stated
+// in [14.6.2(3)]. None of the compilers I've tried so
+// far apparently caught this but HP-UX aCC 3.30 did. The
+// fix was to add 'this->' prefixes in many places.
+// Thanks to Farrokh Nejadlotfi for this!
+//
+// 2001-APR-27 - StreamLoad was calculating the number of BYTES in one
+// case, not characters. Thanks to Pablo Presedo for this.
+//
+// 2001-FEB-23 - Replace() had a bug which caused infinite loops if the
+// source string was empty. Fixed thanks to Eric Nitzsche.
+//
+// 2001-FEB-23 - Scott Hathaway was a huge help in providing me with the
+// ability to build CStdString on Sun Unix systems. He
+// sent me detailed build reports about what works and what
+// does not. If CStdString compiles on your Unix box, you
+// can thank Scott for it.
+//
+// 2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do a
+// range check as CString's does. Now fixed -- thanks!
+//
+// 2000-NOV-07 - Aaron pointed out that I was calling static member
+// functions of char_traits via a temporary. This was not
+// technically wrong, but it was unnecessary and caused
+// problems for poor old buggy VC5. Thanks Aaron!
+//
+// 2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match
+// what the CString::Find code really ends up doing. I was
+// trying to match the docs. Now I match the CString code
+// - Joe also caught me truncating strings for GetBuffer() calls
+// when the supplied length was less than the current length.
+//
+// 2000-MAY-25 - Better support for STLPORT's Standard library distribution
+// - Got rid of the NSP macro - it interfered with Koenig lookup
+// - Thanks to Joe Woodbury for catching a TrimLeft() bug that
+// I introduced in January. Empty strings were not getting
+// trimmed
+//
+// 2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind
+// is supposed to be a const function.
+//
+// 2000-MAR-07 - Thanks to Ullrich Poll�hne for catching a range bug in one
+// of the overloads of assign.
+//
+// 2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior!
+// Thanks to Todd Heckel for helping out with this.
+//
+// 2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the
+// Trim() function more efficient.
+// - Thanks to Jeff Kohn for prompting me to find and fix a typo
+// in one of the addition operators that takes _bstr_t.
+// - Got rid of the .CPP file - you only need StdString.h now!
+//
+// 1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem
+// with my implementation of CStdString::FormatV in which
+// resulting string might not be properly NULL terminated.
+//
+// 1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment
+// bug that MS has not fixed. CStdString did nothing to fix
+// it either but it does now! The bug was: create a string
+// longer than 31 characters, get a pointer to it (via c_str())
+// and then assign that pointer to the original string object.
+// The resulting string would be empty. Not with CStdString!
+//
+// 1999-OCT-06 - BufferSet was erasing the string even when it was merely
+// supposed to shrink it. Fixed. Thanks to Chris Conti.
+// - Some of the Q172398 fixes were not checking for assignment-
+// to-self. Fixed. Thanks to Baptiste Lepilleur.
+//
+// 1999-AUG-20 - Improved Load() function to be more efficient by using
+// SizeOfResource(). Thanks to Rich Zuris for this.
+// - Corrected resource ID constructor, again thanks to Rich.
+// - Fixed a bug that occurred with UNICODE characters above
+// the first 255 ANSI ones. Thanks to Craig Watson.
+// - Added missing overloads of TrimLeft() and TrimRight().
+// Thanks to Karim Ratib for pointing them out
+//
+// 1999-JUL-21 - Made all calls to GetBuf() with no args check length first.
+//
+// 1999-JUL-10 - Improved MFC/ATL independence of conversion macros
+// - Added SS_NO_REFCOUNT macro to allow you to disable any
+// reference-counting your basic_string<> impl. may do.
+// - Improved ReleaseBuffer() to be as forgiving as CString.
+// Thanks for Fan Xia for helping me find this and to
+// Matthew Williams for pointing it out directly.
+//
+// 1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in
+// ToLower/ToUpper. They should call GetBuf() instead of
+// data() in order to ensure the changed string buffer is not
+// reference-counted (in those implementations that refcount).
+//
+// 1999-JUL-01 - Added a true CString facade. Now you can use CStdString as
+// a drop-in replacement for CString. If you find this useful,
+// you can thank Chris Sells for finally convincing me to give
+// in and implement it.
+// - Changed operators << and >> (for MFC CArchive) to serialize
+// EXACTLY as CString's do. So now you can send a CString out
+// to a CArchive and later read it in as a CStdString. I have
+// no idea why you would want to do this but you can.
+//
+// 1999-JUN-21 - Changed the CStdString class into the CStdStr template.
+// - Fixed FormatV() to correctly decrement the loop counter.
+// This was harmless bug but a bug nevertheless. Thanks to
+// Chris (of Melbsys) for pointing it out
+// - Changed Format() to try a normal stack-based array before
+// using to _alloca().
+// - Updated the text conversion macros to properly use code
+// pages and to fit in better in MFC/ATL builds. In other
+// words, I copied Microsoft's conversion stuff again.
+// - Added equivalents of CString::GetBuffer, GetBufferSetLength
+// - new sscpy() replacement of CStdString::CopyString()
+// - a Trim() function that combines TrimRight() and TrimLeft().
+//
+// 1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace()
+// instead of _isspace() Thanks to Dave Plummer for this.
+//
+// 1999-FEB-26 - Removed errant line (left over from testing) that #defined
+// _MFC_VER. Thanks to John C Sipos for noticing this.
+//
+// 1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that
+// caused infinite recursion and stack overflow
+// - Added member functions to simplify the process of
+// persisting CStdStrings to/from DCOM IStream interfaces
+// - Added functional objects (e.g. StdStringLessNoCase) that
+// allow CStdStrings to be used as keys STL map objects with
+// case-insensitive comparison
+// - Added array indexing operators (i.e. operator[]). I
+// originally assumed that these were unnecessary and would be
+// inherited from basic_string. However, without them, Visual
+// C++ complains about ambiguous overloads when you try to use
+// them. Thanks to Julian Selman to pointing this out.
+//
+// 1998-FEB-?? - Added overloads of assign() function to completely account
+// for Q172398 bug. Thanks to "Pete the Plumber" for this
+//
+// 1998-FEB-?? - Initial submission
+//
+// COPYRIGHT:
+// 2002 Joseph M. O'Leary. This code is 100% free. Use it anywhere you
+// want. Rewrite it, restructure it, whatever. If you can write software
+// that makes money off of it, good for you. I kinda like capitalism.
+// Please don't blame me if it causes your $30 billion dollar satellite
+// explode in orbit. If you redistribute it in any form, I'd appreciate it
+// if you would leave this notice here.
+// =============================================================================
+
+// Avoid multiple inclusion
+
+#ifndef STDSTRING_H
+#define STDSTRING_H
+
+// When using VC, turn off browser references
+// Turn off unavoidable compiler warnings
+
+#if defined(_MSC_VER) && (_MSC_VER > 1100)
+ #pragma component(browser, off, references, "CStdString")
+ #pragma warning (disable : 4290) // C++ Exception Specification ignored
+ #pragma warning (disable : 4127) // Conditional expression is constant
+ #pragma warning (disable : 4097) // typedef name used as synonym for class name
+#endif
+
+// Borland warnings to turn off
+
+#ifdef __BORLANDC__
+ #pragma option push -w-inl
+// #pragma warn -inl // Turn off inline function warnings
+#endif
+
+// SS_IS_INTRESOURCE
+// -----------------
+// A copy of IS_INTRESOURCE from VC7. Because old VC6 version of winuser.h
+// doesn't have this.
+
+#define SS_IS_INTRESOURCE(_r) (false)
+
+#if !defined (SS_ANSI) && defined(_MSC_VER)
+ #undef SS_IS_INTRESOURCE
+ #if defined(_WIN64)
+ #define SS_IS_INTRESOURCE(_r) (((unsigned __int64)(_r) >> 16) == 0)
+ #else
+ #define SS_IS_INTRESOURCE(_r) (((unsigned long)(_r) >> 16) == 0)
+ #endif
+#endif
+
+
+// MACRO: SS_UNSIGNED
+// ------------------
+// This macro causes the addition of a constructor and assignment operator
+// which take unsigned characters. CString has such functions and in order
+// to provide maximum CString-compatability, this code needs them as well.
+// In practice you will likely never need these functions...
+
+//#define SS_UNSIGNED
+
+#ifdef SS_ALLOW_UNSIGNED_CHARS
+ #define SS_UNSIGNED
+#endif
+
+// MACRO: SS_SAFE_FORMAT
+// ---------------------
+// This macro provides limited compatability with a questionable CString
+// "feature". You can define it in order to avoid a common problem that
+// people encounter when switching from CString to CStdString.
+//
+// To illustrate the problem -- With CString, you can do this:
+//
+// CString sName("Joe");
+// CString sTmp;
+// sTmp.Format("My name is %s", sName); // WORKS!
+//
+// However if you were to try this with CStdString, your program would
+// crash.
+//
+// CStdString sName("Joe");
+// CStdString sTmp;
+// sTmp.Format("My name is %s", sName); // CRASHES!
+//
+// You must explicitly call c_str() or cast the object to the proper type
+//
+// sTmp.Format("My name is %s", sName.c_str()); // WORKS!
+// sTmp.Format("My name is %s", static_cast<PCSTR>(sName));// WORKS!
+// sTmp.Format("My name is %s", (PCSTR)sName); // WORKS!
+//
+// This is because it is illegal to pass anything but a POD type as a
+// variadic argument to a variadic function (i.e. as one of the "..."
+// arguments). The type const char* is a POD type. The type CStdString
+// is not. Of course, neither is the type CString, but CString lets you do
+// it anyway due to the way they laid out the class in binary. I have no
+// control over this in CStdString since I derive from whatever
+// implementation of basic_string is available.
+//
+// However if you have legacy code (which does this) that you want to take
+// out of the MFC world and you don't want to rewrite all your calls to
+// Format(), then you can define this flag and it will no longer crash.
+//
+// Note however that this ONLY works for Format(), not sprintf, fprintf,
+// etc. If you pass a CStdString object to one of those functions, your
+// program will crash. Not much I can do to get around this, short of
+// writing substitutes for those functions as well.
+
+#define SS_SAFE_FORMAT // use new template style Format() function
+
+
+// MACRO: SS_NO_IMPLICIT_CAST
+// --------------------------
+// Some people don't like the implicit cast to const char* (or rather to
+// const CT*) that CStdString (and MFC's CString) provide. That was the
+// whole reason I created this class in the first place, but hey, whatever
+// bakes your cake. Just #define this macro to get rid of the the implicit
+// cast.
+
+//#define SS_NO_IMPLICIT_CAST // gets rid of operator const CT*()
+
+
+// MACRO: SS_NO_REFCOUNT
+// ---------------------
+// turns off reference counting at the assignment level. Only needed
+// for the version of basic_string<> that comes with Visual C++ versions
+// 6.0 or earlier, and only then in some heavily multithreaded scenarios.
+// Uncomment it if you feel you need it.
+
+//#define SS_NO_REFCOUNT
+
+// MACRO: SS_WIN32
+// ---------------
+// When this flag is set, we are building code for the Win32 platform and
+// may use Win32 specific functions (such as LoadString). This gives us
+// a couple of nice extras for the code.
+//
+// Obviously, Microsoft's is not the only compiler available for Win32 out
+// there. So I can't just check to see if _MSC_VER is defined to detect
+// if I'm building on Win32. So for now, if you use MS Visual C++ or
+// Borland's compiler, I turn this on. Otherwise you may turn it on
+// yourself, if you prefer
+
+#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WIN32)
+ #define SS_WIN32
+#endif
+
+// MACRO: SS_ANSI
+// --------------
+// When this macro is defined, the code attempts only to use ANSI/ISO
+// standard library functions to do it's work. It will NOT attempt to use
+// any Win32 of Visual C++ specific functions -- even if they are
+// available. You may define this flag yourself to prevent any Win32
+// of VC++ specific functions from being called.
+
+// If we're not on Win32, we MUST use an ANSI build
+
+#ifndef SS_WIN32
+ #if !defined(SS_NO_ANSI)
+ #define SS_ANSI
+ #endif
+#endif
+
+// MACRO: SS_ALLOCA
+// ----------------
+// Some implementations of the Standard C Library have a non-standard
+// function known as alloca(). This functions allows one to allocate a
+// variable amount of memory on the stack. It is needed to implement
+// the ASCII/MBCS conversion macros.
+//
+// I wanted to find some way to determine automatically if alloca() is
+// available on this platform via compiler flags but that is asking for
+// trouble. The crude test presented here will likely need fixing on
+// other platforms. Therefore I'll leave it up to you to fiddle with
+// this test to determine if it exists. Just make sure SS_ALLOCA is or
+// is not defined as appropriate and you control this feature.
+
+#if defined(_MSC_VER) && !defined(SS_ANSI)
+ #define SS_ALLOCA
+#endif
+
+
+// MACRO: SS_MBCS
+// --------------
+// Setting this macro means you are using MBCS characters. In MSVC builds,
+// this macro gets set automatically by detection of the preprocessor flag
+// _MBCS. For other platforms you may set it manually if you wish. The
+// only effect it currently has is to cause the allocation of more space
+// for wchar_t --> char conversions.
+// Note that MBCS does not mean UNICODE.
+//
+// #define SS_MBCS
+//
+
+#ifdef _MBCS
+ #define SS_MBCS
+#endif
+
+
+// MACRO SS_NO_LOCALE
+// ------------------
+// If your implementation of the Standard C++ Library lacks the <locale> header,
+// you can #define this macro to make your code build properly. Note that this
+// is some of my newest code and frankly I'm not very sure of it, though it does
+// pass my unit tests.
+
+// #define SS_NO_LOCALE
+
+
+// Compiler Error regarding _UNICODE and UNICODE
+// -----------------------------------------------
+// Microsoft header files are screwy. Sometimes they depend on a preprocessor
+// flag named "_UNICODE". Other times they check "UNICODE" (note the lack of
+// leading underscore in the second version". In several places, they silently
+// "synchronize" these two flags this by defining one of the other was defined.
+// In older version of this header, I used to try to do the same thing.
+//
+// However experience has taught me that this is a bad idea. You get weird
+// compiler errors that seem to indicate things like LPWSTR and LPTSTR not being
+// equivalent in UNICODE builds, stuff like that (when they MUST be in a proper
+// UNICODE build). You end up scratching your head and saying, "But that HAS
+// to compile!".
+//
+// So what should you do if you get this error?
+//
+// Make sure that both macros (_UNICODE and UNICODE) are defined before this
+// file is included. You can do that by either
+//
+// a) defining both yourself before any files get included
+// b) including the proper MS headers in the proper order
+// c) including this file before any other file, uncommenting
+// the #defines below, and commenting out the #errors
+//
+// Personally I recommend solution a) but it's your call.
+
+#ifdef _MSC_VER
+ #if defined (_UNICODE) && !defined (UNICODE)
+ #error UNICODE defined but not UNICODE
+ // #define UNICODE // no longer silently fix this
+ #endif
+ #if defined (UNICODE) && !defined (_UNICODE)
+ #error Warning, UNICODE defined but not _UNICODE
+ // #define _UNICODE // no longer silently fix this
+ #endif
+#endif
+
+
+// -----------------------------------------------------------------------------
+// MIN and MAX. The Standard C++ template versions go by so many names (at
+// at least in the MS implementation) that you never know what's available
+// -----------------------------------------------------------------------------
+template<class Type>
+inline const Type& SSMIN(const Type& arg1, const Type& arg2)
+{
+ return arg2 < arg1 ? arg2 : arg1;
+}
+template<class Type>
+inline const Type& SSMAX(const Type& arg1, const Type& arg2)
+{
+ return arg2 > arg1 ? arg2 : arg1;
+}
+
+// If they have not #included W32Base.h (part of my W32 utility library) then
+// we need to define some stuff. Otherwise, this is all defined there.
+
+#if !defined(W32BASE_H)
+
+ // If they want us to use only standard C++ stuff (no Win32 stuff)
+
+ #ifdef SS_ANSI
+
+ // On Win32 we have TCHAR.H so just include it. This is NOT violating
+ // the spirit of SS_ANSI as we are not calling any Win32 functions here.
+
+ #ifdef SS_WIN32
+
+ #include <TCHAR.H>
+ #include <WTYPES.H>
+ #ifndef STRICT
+ #define STRICT
+ #endif
+
+ // ... but on non-Win32 platforms, we must #define the types we need.
+
+ #else
+
+ typedef const char* PCSTR;
+ typedef char* PSTR;
+ typedef const wchar_t* PCWSTR;
+ typedef wchar_t* PWSTR;
+ #ifdef UNICODE
+ typedef wchar_t TCHAR;
+ #else
+ typedef char TCHAR;
+ #endif
+ typedef wchar_t OLECHAR;
+
+ #endif // #ifndef _WIN32
+
+
+ // Make sure ASSERT and verify are defined using only ANSI stuff
+
+ #ifndef ASSERT
+ #include <assert.h>
+ #define ASSERT(f) assert((f))
+ #endif
+ #ifndef VERIFY
+ #ifdef _DEBUG
+ #define VERIFY(x) ASSERT((x))
+ #else
+ #define VERIFY(x) x
+ #endif
+ #endif
+
+ #else // ...else SS_ANSI is NOT defined
+
+ #include <TCHAR.H>
+ #include <WTYPES.H>
+ #ifndef STRICT
+ #define STRICT
+ #endif
+
+ // Make sure ASSERT and verify are defined
+
+ #ifndef ASSERT
+ #include <crtdbg.h>
+ #define ASSERT(f) _ASSERTE((f))
+ #endif
+ #ifndef VERIFY
+ #ifdef _DEBUG
+ #define VERIFY(x) ASSERT((x))
+ #else
+ #define VERIFY(x) x
+ #endif
+ #endif
+
+ #endif // #ifdef SS_ANSI
+
+ #ifndef UNUSED
+ #define UNUSED(x) x
+ #endif
+
+#endif // #ifndef W32BASE_H
+
+// Standard headers needed
+
+#include <string> // basic_string
+#include <algorithm> // for_each, etc.
+#include <functional> // for StdStringLessNoCase, et al
+#ifndef SS_NO_LOCALE
+ #include <locale> // for various facets
+#endif
+
+// If this is a recent enough version of VC include comdef.h, so we can write
+// member functions to deal with COM types & compiler support classes e.g.
+// _bstr_t
+
+#if defined (_MSC_VER) && (_MSC_VER >= 1100)
+ #include <comdef.h>
+ #define SS_INC_COMDEF // signal that we #included MS comdef.h file
+ #define STDSTRING_INC_COMDEF
+ #define SS_NOTHROW __declspec(nothrow)
+#else
+ #define SS_NOTHROW
+#endif
+
+#ifndef TRACE
+ #define TRACE_DEFINED_HERE
+ #define TRACE
+#endif
+
+// Microsoft defines PCSTR, PCWSTR, etc, but no PCTSTR. I hate to use the
+// versions with the "L" in front of them because that's a leftover from Win 16
+// days, even though it evaluates to the same thing. Therefore, Define a PCSTR
+// as an LPCTSTR.
+
+#if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)
+ typedef const TCHAR* PCTSTR;
+ #define PCTSTR_DEFINED
+#endif
+
+#if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)
+ typedef const OLECHAR* PCOLESTR;
+ #define PCOLESTR_DEFINED
+#endif
+
+#if !defined(POLESTR) && !defined(POLESTR_DEFINED)
+ typedef OLECHAR* POLESTR;
+ #define POLESTR_DEFINED
+#endif
+
+#if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)
+ typedef const unsigned char* PCUSTR;
+ typedef unsigned char* PUSTR;
+ #define PCUSTR_DEFINED
+#endif
+
+
+// SGI compiler 7.3 doesnt know these types - oh and btw, remember to use
+// -LANG:std in the CXX Flags
+#if defined(__sgi)
+ typedef unsigned long DWORD;
+ typedef void * LPCVOID;
+#endif
+
+
+// SS_USE_FACET macro and why we need it:
+//
+// Since I'm a good little Standard C++ programmer, I use locales. Thus, I
+// need to make use of the use_facet<> template function here. Unfortunately,
+// this need is complicated by the fact the MS' implementation of the Standard
+// C++ Library has a non-standard version of use_facet that takes more
+// arguments than the standard dictates. Since I'm trying to write CStdString
+// to work with any version of the Standard library, this presents a problem.
+//
+// The upshot of this is that I can't do 'use_facet' directly. The MS' docs
+// tell me that I have to use a macro, _USE() instead. Since _USE obviously
+// won't be available in other implementations, this means that I have to write
+// my OWN macro -- SS_USE_FACET -- that evaluates either to _USE or to the
+// standard, use_facet.
+//
+// If you are having trouble with the SS_USE_FACET macro, in your implementation
+// of the Standard C++ Library, you can define your own version of SS_USE_FACET.
+
+#ifndef schMSG
+ #define schSTR(x) #x
+ #define schSTR2(x) schSTR(x)
+ #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)
+#endif
+
+#ifndef SS_USE_FACET
+
+ // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for
+ // all MSVC builds, erroneously in my opinion. It causes problems for
+ // my SS_ANSI builds. In my code, I always comment out that line. You'll
+ // find it in \stlport\config\stl_msvc.h
+
+ #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )
+
+ #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)
+ #ifdef SS_ANSI
+ #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)
+ #endif
+ #endif
+ #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
+
+ #elif defined(_MSC_VER )
+
+ #define SS_USE_FACET(loc, fac) std::_USE(loc, fac)
+
+ // ...and
+ #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)
+
+ #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)
+
+ #else
+
+ #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
+
+ #endif
+
+#endif
+
+// =============================================================================
+// UNICODE/MBCS conversion macros. Made to work just like the MFC/ATL ones.
+// =============================================================================
+
+#include <wchar.h> // Added to Std Library with Amendment #1.
+
+// First define the conversion helper functions. We define these regardless of
+// any preprocessor macro settings since their names won't collide.
+
+// Not sure if we need all these headers. I believe ANSI says we do.
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <wctype.h>
+#include <ctype.h>
+#include <stdlib.h>
+#ifndef va_start
+ #include <varargs.h>
+#endif
+
+
+#ifdef SS_NO_LOCALE
+
+ #if defined(_WIN32) || defined (_WIN32_WCE)
+
+ inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCSTR pSrcA, int nSrc,
+ UINT acp=CP_ACP)
+ {
+ ASSERT(0 != pSrcA);
+ ASSERT(0 != pDstW);
+ pDstW[0] = '\0';
+ MultiByteToWideChar(acp, 0, pSrcA, nSrc, pDstW, nDst);
+ return pDstW;
+ }
+ inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCUSTR pSrcA, int nSrc,
+ UINT acp=CP_ACP)
+ {
+ return StdCodeCvt(pDstW, nDst, (PCSTR)pSrcA, nSrc, acp);
+ }
+
+ inline PSTR StdCodeCvt(PSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
+ UINT acp=CP_ACP)
+ {
+ ASSERT(0 != pDstA);
+ ASSERT(0 != pSrcW);
+ pDstA[0] = '\0';
+ WideCharToMultiByte(acp, 0, pSrcW, nSrc, pDstA, nDst, 0, 0);
+ return pDstA;
+ }
+ inline PUSTR StdCodeCvt(PUSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
+ UINT acp=CP_ACP)
+ {
+ return (PUSTR)StdCodeCvt((PSTR)pDstA, nDst, pSrcW, nSrc, acp);
+ }
+ #else
+ #endif
+
+#else
+
+ // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte
+ // and MultiByteToWideChar but uses locales in SS_ANSI
+ // builds. There are a number of overloads.
+ // First argument is the destination buffer.
+ // Second argument is the source buffer
+ //#if defined (SS_ANSI) || !defined (SS_WIN32)
+
+ // 'SSCodeCvt' - shorthand name for the codecvt facet we use
+
+ typedef std::codecvt<wchar_t, char, mbstate_t> SSCodeCvt;
+
+ inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCSTR pSrcA, int nSrc,
+ const std::locale& loc=std::locale())
+ {
+ ASSERT(0 != pSrcA);
+ ASSERT(0 != pDstW);
+
+ pDstW[0] = '\0';
+
+ if ( nSrc > 0 )
+ {
+ PCSTR pNextSrcA = pSrcA;
+ PWSTR pNextDstW = pDstW;
+ SSCodeCvt::result res = SSCodeCvt::ok;
+ const SSCodeCvt& conv = SS_USE_FACET(loc, SSCodeCvt);
+ SSCodeCvt::state_type st= { 0 };
+ res = conv.in(st,
+ pSrcA, pSrcA + nSrc, pNextSrcA,
+ pDstW, pDstW + nDst, pNextDstW);
+#ifdef _LINUX
+#define ASSERT2(a) if (!(a)) {fprintf(stderr, "StdString: Assertion Failed on line %d\n", __LINE__);}
+#else
+#define ASSERT2 ASSERT
+#endif
+ ASSERT2(SSCodeCvt::ok == res);
+ ASSERT2(SSCodeCvt::error != res);
+ ASSERT2(pNextDstW >= pDstW);
+ ASSERT2(pNextSrcA >= pSrcA);
+#undef ASSERT2
+ // Null terminate the converted string
+
+ if ( pNextDstW - pDstW > nDst )
+ *(pDstW + nDst) = '\0';
+ else
+ *pNextDstW = '\0';
+ }
+ return pDstW;
+ }
+ inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCUSTR pSrcA, int nSrc,
+ const std::locale& loc=std::locale())
+ {
+ return StdCodeCvt(pDstW, nDst, (PCSTR)pSrcA, nSrc, loc);
+ }
+
+ inline PSTR StdCodeCvt(PSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
+ const std::locale& loc=std::locale())
+ {
+ ASSERT(0 != pDstA);
+ ASSERT(0 != pSrcW);
+
+ pDstA[0] = '\0';
+
+ if ( nSrc > 0 )
+ {
+ PSTR pNextDstA = pDstA;
+ PCWSTR pNextSrcW = pSrcW;
+ SSCodeCvt::result res = SSCodeCvt::ok;
+ const SSCodeCvt& conv = SS_USE_FACET(loc, SSCodeCvt);
+ SSCodeCvt::state_type st= { 0 };
+ res = conv.out(st,
+ pSrcW, pSrcW + nSrc, pNextSrcW,
+ pDstA, pDstA + nDst, pNextDstA);
+#ifdef _LINUX
+#define ASSERT2(a) if (!(a)) {fprintf(stderr, "StdString: Assertion Failed on line %d\n", __LINE__);}
+#else
+#define ASSERT2 ASSERT
+#endif
+ ASSERT2(SSCodeCvt::error != res);
+ ASSERT2(SSCodeCvt::ok == res); // strict, comment out for sanity
+ ASSERT2(pNextDstA >= pDstA);
+ ASSERT2(pNextSrcW >= pSrcW);
+#undef ASSERT2
+
+ // Null terminate the converted string
+
+ if ( pNextDstA - pDstA > nDst )
+ *(pDstA + nDst) = '\0';
+ else
+ *pNextDstA = '\0';
+ }
+ return pDstA;
+ }
+
+ inline PUSTR StdCodeCvt(PUSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
+ const std::locale& loc=std::locale())
+ {
+ return (PUSTR)StdCodeCvt((PSTR)pDstA, nDst, pSrcW, nSrc, loc);
+ }
+
+#endif
+
+
+
+// Unicode/MBCS conversion macros are only available on implementations of
+// the "C" library that have the non-standard _alloca function. As far as I
+// know that's only Microsoft's though I've heard that the function exists
+// elsewhere.
+
+#if defined(SS_ALLOCA) && !defined SS_NO_CONVERSION
+
+ #include <malloc.h> // needed for _alloca
+
+ // Define our conversion macros to look exactly like Microsoft's to
+ // facilitate using this stuff both with and without MFC/ATL
+
+ #ifdef _CONVERSION_USES_THREAD_LOCALE
+
+ #ifndef _DEBUG
+ #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \
+ _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa
+ #else
+ #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\
+ _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
+ #endif
+ #define SSA2W(pa) (\
+ ((_pa = pa) == 0) ? 0 : (\
+ _cvt = (sslen(_pa)),\
+ StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
+ _pa, _cvt, _acp)))
+ #define SSW2A(pw) (\
+ ((_pw = pw) == 0) ? 0 : (\
+ _cvt = sslen(_pw), \
+ StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
+ _pw, _cvt, _acp)))
+ #else
+
+ #ifndef _DEBUG
+ #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\
+ PCWSTR _pw; _pw; PCSTR _pa; _pa
+ #else
+ #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \
+ _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
+ #endif
+ #define SSA2W(pa) (\
+ ((_pa = pa) == 0) ? 0 : (\
+ _cvt = (sslen(_pa)),\
+ StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
+ _pa, _cvt)))
+ #define SSW2A(pw) (\
+ ((_pw = pw) == 0) ? 0 : (\
+ _cvt = (sslen(_pw)),\
+ StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
+ _pw, _cvt)))
+ #endif
+
+ #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))
+ #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))
+
+ #ifdef UNICODE
+ #define SST2A SSW2A
+ #define SSA2T SSA2W
+ #define SST2CA SSW2CA
+ #define SSA2CT SSA2CW
+ // (Did you get a compiler error here about not being able to convert
+ // PTSTR into PWSTR? Then your _UNICODE and UNICODE flags are messed
+ // up. Best bet: #define BOTH macros before including any MS headers.)
+ inline PWSTR SST2W(PTSTR p) { return p; }
+ inline PTSTR SSW2T(PWSTR p) { return p; }
+ inline PCWSTR SST2CW(PCTSTR p) { return p; }
+ inline PCTSTR SSW2CT(PCWSTR p) { return p; }
+ #else
+ #define SST2W SSA2W
+ #define SSW2T SSW2A
+ #define SST2CW SSA2CW
+ #define SSW2CT SSW2CA
+ inline PSTR SST2A(PTSTR p) { return p; }
+ inline PTSTR SSA2T(PSTR p) { return p; }
+ inline PCSTR SST2CA(PCTSTR p) { return p; }
+ inline PCTSTR SSA2CT(PCSTR p) { return p; }
+ #endif // #ifdef UNICODE
+
+ #if defined(UNICODE)
+ // in these cases the default (TCHAR) is the same as OLECHAR
+ inline PCOLESTR SST2COLE(PCTSTR p) { return p; }
+ inline PCTSTR SSOLE2CT(PCOLESTR p) { return p; }
+ inline POLESTR SST2OLE(PTSTR p) { return p; }
+ inline PTSTR SSOLE2T(POLESTR p) { return p; }
+ #elif defined(OLE2ANSI)
+ // in these cases the default (TCHAR) is the same as OLECHAR
+ inline PCOLESTR SST2COLE(PCTSTR p) { return p; }
+ inline PCTSTR SSOLE2CT(PCOLESTR p) { return p; }
+ inline POLESTR SST2OLE(PTSTR p) { return p; }
+ inline PTSTR SSOLE2T(POLESTR p) { return p; }
+ #else
+ //CharNextW doesn't work on Win95 so we use this
+ #define SST2COLE(pa) SSA2CW((pa))
+ #define SST2OLE(pa) SSA2W((pa))
+ #define SSOLE2CT(po) SSW2CA((po))
+ #define SSOLE2T(po) SSW2A((po))
+ #endif
+
+ #ifdef OLE2ANSI
+ #define SSW2OLE SSW2A
+ #define SSOLE2W SSA2W
+ #define SSW2COLE SSW2CA
+ #define SSOLE2CW SSA2CW
+ inline POLESTR SSA2OLE(PSTR p) { return p; }
+ inline PSTR SSOLE2A(POLESTR p) { return p; }
+ inline PCOLESTR SSA2COLE(PCSTR p) { return p; }
+ inline PCSTR SSOLE2CA(PCOLESTR p){ return p; }
+ #else
+ #define SSA2OLE SSA2W
+ #define SSOLE2A SSW2A
+ #define SSA2COLE SSA2CW
+ #define SSOLE2CA SSW2CA
+ inline POLESTR SSW2OLE(PWSTR p) { return p; }
+ inline PWSTR SSOLE2W(POLESTR p) { return p; }
+ inline PCOLESTR SSW2COLE(PCWSTR p) { return p; }
+ inline PCWSTR SSOLE2CW(PCOLESTR p){ return p; }
+ #endif
+
+ // Above we've defined macros that look like MS' but all have
+ // an 'SS' prefix. Now we need the real macros. We'll either
+ // get them from the macros above or from MFC/ATL.
+
+ #if defined (USES_CONVERSION)
+
+ #define _NO_STDCONVERSION // just to be consistent
+
+ #else
+
+ #ifdef _MFC_VER
+
+ #include <afxconv.h>
+ #define _NO_STDCONVERSION // just to be consistent
+
+ #else
+
+ #define USES_CONVERSION SSCVT
+ #define A2CW SSA2CW
+ #define W2CA SSW2CA
+ #define T2A SST2A
+ #define A2T SSA2T
+ #define T2W SST2W
+ #define W2T SSW2T
+ #define T2CA SST2CA
+ #define A2CT SSA2CT
+ #define T2CW SST2CW
+ #define W2CT SSW2CT
+ #define ocslen sslen
+ #define ocscpy sscpy
+ #define T2COLE SST2COLE
+ #define OLE2CT SSOLE2CT
+ #define T2OLE SST2COLE
+ #define OLE2T SSOLE2CT
+ #define A2OLE SSA2OLE
+ #define OLE2A SSOLE2A
+ #define W2OLE SSW2OLE
+ #define OLE2W SSOLE2W
+ #define A2COLE SSA2COLE
+ #define OLE2CA SSOLE2CA
+ #define W2COLE SSW2COLE
+ #define OLE2CW SSOLE2CW
+
+ #endif // #ifdef _MFC_VER
+ #endif // #ifndef USES_CONVERSION
+#endif // #ifndef SS_NO_CONVERSION
+
+// Define ostring - generic name for std::basic_string<OLECHAR>
+
+#if !defined(ostring) && !defined(OSTRING_DEFINED)
+ typedef std::basic_string<OLECHAR> ostring;
+ #define OSTRING_DEFINED
+#endif
+
+// StdCodeCvt when there's no conversion to be done
+template <typename T>
+inline T* StdCodeCvt(T* pDst, int nDst, const T* pSrc, int nSrc)
+{
+ int nChars = SSMIN(nSrc, nDst);
+
+ if ( nChars > 0 )
+ {
+ pDst[0] = '\0';
+ std::basic_string<T>::traits_type::copy(pDst, pSrc, nChars);
+// std::char_traits<T>::copy(pDst, pSrc, nChars);
+ pDst[nChars] = '\0';
+ }
+
+ return pDst;
+}
+inline PSTR StdCodeCvt(PSTR pDst, int nDst, PCUSTR pSrc, int nSrc)
+{
+ return StdCodeCvt(pDst, nDst, (PCSTR)pSrc, nSrc);
+}
+inline PUSTR StdCodeCvt(PUSTR pDst, int nDst, PCSTR pSrc, int nSrc)
+{
+ return (PUSTR)StdCodeCvt((PSTR)pDst, nDst, pSrc, nSrc);
+}
+
+// Define tstring -- generic name for std::basic_string<TCHAR>
+
+#if !defined(tstring) && !defined(TSTRING_DEFINED)
+ typedef std::basic_string<TCHAR> tstring;
+ #define TSTRING_DEFINED
+#endif
+
+// a very shorthand way of applying the fix for KB problem Q172398
+// (basic_string assignment bug)
+
+#if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
+ #define Q172398(x) (x).erase()
+#else
+ #define Q172398(x)
+#endif
+
+// =============================================================================
+// INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES
+//
+// Usually for generic text mapping, we rely on preprocessor macro definitions
+// to map to string functions. However the CStdStr<> template cannot use
+// macro-based generic text mappings because its character types do not get
+// resolved until template processing which comes AFTER macro processing. In
+// other words, the preprocessor macro UNICODE is of little help to us in the
+// CStdStr template
+//
+// Therefore, to keep the CStdStr declaration simple, we have these inline
+// functions. The template calls them often. Since they are inline (and NOT
+// exported when this is built as a DLL), they will probably be resolved away
+// to nothing.
+//
+// Without these functions, the CStdStr<> template would probably have to broken
+// out into two, almost identical classes. Either that or it would be a huge,
+// convoluted mess, with tons of "if" statements all over the place checking the
+// size of template parameter CT.
+// =============================================================================
+
+#ifdef SS_NO_LOCALE
+
+ // --------------------------------------------------------------------------
+ // Win32 GetStringTypeEx wrappers
+ // --------------------------------------------------------------------------
+ inline bool wsGetStringType(LCID lc, DWORD dwT, PCSTR pS, int nSize,
+ WORD* pWd)
+ {
+ return FALSE != GetStringTypeExA(lc, dwT, pS, nSize, pWd);
+ }
+ inline bool wsGetStringType(LCID lc, DWORD dwT, PCWSTR pS, int nSize,
+ WORD* pWd)
+ {
+ return FALSE != GetStringTypeExW(lc, dwT, pS, nSize, pWd);
+ }
+
+
+ template<typename CT>
+ inline bool ssisspace (CT t)
+ {
+ WORD toYourMother;
+ return wsGetStringType(GetThreadLocale(), CT_CTYPE1, &t, 1, &toYourMother)
+ && 0 != (C1_BLANK & toYourMother);
+ }
+
+#endif
+
+// If they defined SS_NO_REFCOUNT, then we must convert all assignments
+
+#if defined (_MSC_VER) && (_MSC_VER < 1300)
+ #ifdef SS_NO_REFCOUNT
+ #define SSREF(x) (x).c_str()
+ #else
+ #define SSREF(x) (x)
+ #endif
+#else
+ #define SSREF(x) (x)
+#endif
+
+// -----------------------------------------------------------------------------
+// sslen: strlen/wcslen wrappers
+// -----------------------------------------------------------------------------
+template<typename CT> inline int sslen(const CT* pT)
+{
+ return 0 == pT ? 0 : (int)std::basic_string<CT>::traits_type::length(pT);
+// return 0 == pT ? 0 : std::char_traits<CT>::length(pT);
+}
+inline SS_NOTHROW int sslen(const std::string& s)
+{
+ return static_cast<int>(s.length());
+}
+inline SS_NOTHROW int sslen(const std::wstring& s)
+{
+ return static_cast<int>(s.length());
+}
+
+// -----------------------------------------------------------------------------
+// sstolower/sstoupper -- convert characters to upper/lower case
+// -----------------------------------------------------------------------------
+
+#ifdef SS_NO_LOCALE
+ inline char sstoupper(char ch) { return (char)::toupper(ch); }
+ inline wchar_t sstoupper(wchar_t ch){ return (wchar_t)::towupper(ch); }
+ inline char sstolower(char ch) { return (char)::tolower(ch); }
+ inline wchar_t sstolower(wchar_t ch){ return (wchar_t)::tolower(ch); }
+#else
+ template<typename CT>
+ inline CT sstolower(const CT& t, const std::locale& loc = std::locale())
+ {
+ return std::tolower<CT>(t, loc);
+ }
+ template<typename CT>
+ inline CT sstoupper(const CT& t, const std::locale& loc = std::locale())
+ {
+ return std::toupper<CT>(t, loc);
+ }
+#endif
+
+// -----------------------------------------------------------------------------
+// ssasn: assignment functions -- assign "sSrc" to "sDst"
+// -----------------------------------------------------------------------------
+typedef std::string::size_type SS_SIZETYPE; // just for shorthand, really
+typedef std::string::pointer SS_PTRTYPE;
+typedef std::wstring::size_type SW_SIZETYPE;
+typedef std::wstring::pointer SW_PTRTYPE;
+
+
+template <typename T>
+inline void ssasn(std::basic_string<T>& sDst, const std::basic_string<T>& sSrc)
+{
+ if ( sDst.c_str() != sSrc.c_str() )
+ {
+ sDst.erase();
+ sDst.assign(SSREF(sSrc));
+ }
+}
+template <typename T>
+inline void ssasn(std::basic_string<T>& sDst, const T *pA)
+{
+ // Watch out for NULLs, as always.
+
+ if ( 0 == pA )
+ {
+ sDst.erase();
+ }
+
+ // If pA actually points to part of sDst, we must NOT erase(), but
+ // rather take a substring
+
+ else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() )
+ {
+ sDst =sDst.substr(static_cast<typename std::basic_string<T>::size_type>(pA-sDst.c_str()));
+ }
+
+ // Otherwise (most cases) apply the assignment bug fix, if applicable
+ // and do the assignment
+
+ else
+ {
+ Q172398(sDst);
+ sDst.assign(pA);
+ }
+}
+inline void ssasn(std::string& sDst, const std::wstring& sSrc)
+{
+ if ( sSrc.empty() )
+ {
+ sDst.erase();
+ }
+ else
+ {
+ int nDst = static_cast<int>(sSrc.size());
+
+ // In MBCS builds, pad the buffer to account for the possibility of
+ // some 3 byte characters. Not perfect but should get most cases.
+
+#ifdef SS_MBCS
+ // In MBCS builds, we don't know how long the destination string will be.
+ nDst = static_cast<int>(static_cast<double>(nDst) * 1.3);
+ sDst.resize(nDst+1);
+ PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,
+ sSrc.c_str(), static_cast<int>(sSrc.size()));
+ sDst.resize(sslen(szCvt));
+#else
+ sDst.resize(nDst+1);
+ StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,
+ sSrc.c_str(), static_cast<int>(sSrc.size()));
+ sDst.resize(sSrc.size());
+#endif
+ }
+}
+inline void ssasn(std::string& sDst, PCWSTR pW)
+{
+ int nSrc = sslen(pW);
+ if ( nSrc > 0 )
+ {
+ int nSrc = sslen(pW);
+ int nDst = nSrc;
+
+ // In MBCS builds, pad the buffer to account for the possibility of
+ // some 3 byte characters. Not perfect but should get most cases.
+
+#ifdef SS_MBCS
+ nDst = static_cast<int>(static_cast<double>(nDst) * 1.3);
+ // In MBCS builds, we don't know how long the destination string will be.
+ sDst.resize(nDst + 1);
+ PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,
+ pW, nSrc);
+ sDst.resize(sslen(szCvt));
+#else
+ sDst.resize(nDst + 1);
+ StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst, pW, nSrc);
+ sDst.resize(nDst);
+#endif
+ }
+ else
+ {
+ sDst.erase();
+ }
+}
+inline void ssasn(std::string& sDst, const int nNull)
+{
+ //UNUSED(nNull);
+ ASSERT(nNull==0);
+ sDst.assign("");
+}
+#undef StrSizeType
+inline void ssasn(std::wstring& sDst, const std::string& sSrc)
+{
+ if ( sSrc.empty() )
+ {
+ sDst.erase();
+ }
+ else
+ {
+ int nSrc = static_cast<int>(sSrc.size());
+ int nDst = nSrc;
+
+ sDst.resize(nSrc+1);
+ PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), nDst,
+ sSrc.c_str(), nSrc);
+
+ sDst.resize(sslen(szCvt));
+ }
+}
+inline void ssasn(std::wstring& sDst, PCSTR pA)
+{
+ int nSrc = sslen(pA);
+
+ if ( 0 == nSrc )
+ {
+ sDst.erase();
+ }
+ else
+ {
+ int nDst = nSrc;
+ sDst.resize(nDst+1);
+ PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), nDst, pA,
+ nSrc);
+
+ sDst.resize(sslen(szCvt));
+ }
+}
+inline void ssasn(std::wstring& sDst, const int nNull)
+{
+ //UNUSED(nNull);
+ ASSERT(nNull==0);
+ sDst.assign(L"");
+}
+
+// -----------------------------------------------------------------------------
+// ssadd: string object concatenation -- add second argument to first
+// -----------------------------------------------------------------------------
+inline void ssadd(std::string& sDst, const std::wstring& sSrc)
+{
+ int nSrc = static_cast<int>(sSrc.size());
+
+ if ( nSrc > 0 )
+ {
+ int nDst = static_cast<int>(sDst.size());
+ int nAdd = nSrc;
+
+ // In MBCS builds, pad the buffer to account for the possibility of
+ // some 3 byte characters. Not perfect but should get most cases.
+
+#ifdef SS_MBCS
+ nAdd = static_cast<int>(static_cast<double>(nAdd) * 1.3);
+ sDst.resize(nDst+nAdd+1);
+ PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst),
+ nAdd, sSrc.c_str(), nSrc);
+ sDst.resize(nDst + sslen(szCvt));
+#else
+ sDst.resize(nDst+nAdd+1);
+ StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst), nAdd, sSrc.c_str(), nSrc);
+ sDst.resize(nDst + nAdd);
+#endif
+ }
+}
+template <typename T>
+inline void ssadd(typename std::basic_string<T>& sDst, const typename std::basic_string<T>& sSrc)
+{
+ sDst += sSrc;
+}
+inline void ssadd(std::string& sDst, PCWSTR pW)
+{
+ int nSrc = sslen(pW);
+ if ( nSrc > 0 )
+ {
+ int nDst = static_cast<int>(sDst.size());
+ int nAdd = nSrc;
+
+#ifdef SS_MBCS
+ nAdd = static_cast<int>(static_cast<double>(nAdd) * 1.3);
+ sDst.resize(nDst + nAdd + 1);
+ PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst),
+ nAdd, pW, nSrc);
+ sDst.resize(nDst + sslen(szCvt));
+#else
+ sDst.resize(nDst + nAdd + 1);
+ StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst), nAdd, pW, nSrc);
+ sDst.resize(nDst + nSrc);
+#endif
+ }
+}
+template <typename T>
+inline void ssadd(typename std::basic_string<T>& sDst, const T *pA)
+{
+ if ( pA )
+ {
+ // If the string being added is our internal string or a part of our
+ // internal string, then we must NOT do any reallocation without
+ // first copying that string to another object (since we're using a
+ // direct pointer)
+
+ if ( pA >= sDst.c_str() && pA <= sDst.c_str()+sDst.length())
+ {
+ if ( sDst.capacity() <= sDst.size()+sslen(pA) )
+ sDst.append(std::basic_string<T>(pA));
+ else
+ sDst.append(pA);
+ }
+ else
+ {
+ sDst.append(pA);
+ }
+ }
+}
+inline void ssadd(std::wstring& sDst, const std::string& sSrc)
+{
+ if ( !sSrc.empty() )
+ {
+ int nSrc = static_cast<int>(sSrc.size());
+ int nDst = static_cast<int>(sDst.size());
+
+ sDst.resize(nDst + nSrc + 1);
+#ifdef SS_MBCS
+ PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst),
+ nSrc, sSrc.c_str(), nSrc+1);
+ sDst.resize(nDst + sslen(szCvt));
+#else
+ StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst), nSrc, sSrc.c_str(), nSrc+1);
+ sDst.resize(nDst + nSrc);
+#endif
+ }
+}
+inline void ssadd(std::wstring& sDst, PCSTR pA)
+{
+ int nSrc = sslen(pA);
+
+ if ( nSrc > 0 )
+ {
+ int nDst = static_cast<int>(sDst.size());
+
+ sDst.resize(nDst + nSrc + 1);
+#ifdef SS_MBCS
+ PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst),
+ nSrc, pA, nSrc+1);
+ sDst.resize(nDst + sslen(szCvt));
+#else
+ StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst), nSrc, pA, nSrc+1);
+ sDst.resize(nDst + nSrc);
+#endif
+ }
+}
+
+// -----------------------------------------------------------------------------
+// sscmp: comparison (case sensitive, not affected by locale)
+// -----------------------------------------------------------------------------
+template<typename CT>
+inline int sscmp(const CT* pA1, const CT* pA2)
+{
+ CT f;
+ CT l;
+
+ do
+ {
+ f = *(pA1++);
+ l = *(pA2++);
+ } while ( (f) && (f == l) );
+
+ return (int)(f - l);
+}
+
+// -----------------------------------------------------------------------------
+// ssicmp: comparison (case INsensitive, not affected by locale)
+// -----------------------------------------------------------------------------
+template<typename CT>
+inline int ssicmp(const CT* pA1, const CT* pA2)
+{
+ // Using the "C" locale = "not affected by locale"
+
+ std::locale loc = std::locale::classic();
+ const std::ctype<CT>& ct = SS_USE_FACET(loc, std::ctype<CT>);
+ CT f;
+ CT l;
+
+ do
+ {
+ f = ct.tolower(*(pA1++));
+ l = ct.tolower(*(pA2++));
+ } while ( (f) && (f == l) );
+
+ return (int)(f - l);
+}
+
+// -----------------------------------------------------------------------------
+// ssupr/sslwr: Uppercase/Lowercase conversion functions
+// -----------------------------------------------------------------------------
+
+template<typename CT>
+inline void sslwr(CT* pT, size_t nLen, const std::locale& loc=std::locale())
+{
+ SS_USE_FACET(loc, std::ctype<CT>).tolower(pT, pT+nLen);
+}
+template<typename CT>
+inline void ssupr(CT* pT, size_t nLen, const std::locale& loc=std::locale())
+{
+ SS_USE_FACET(loc, std::ctype<CT>).toupper(pT, pT+nLen);
+}
+
+// -----------------------------------------------------------------------------
+// vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents. In standard
+// builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.
+//
+// -----------------------------------------------------------------------------
+// Borland's headers put some ANSI "C" functions in the 'std' namespace.
+// Promote them to the global namespace so we can use them here.
+
+#if defined(__BORLANDC__)
+ using std::vsprintf;
+ using std::vswprintf;
+#endif
+
+ // GNU is supposed to have vsnprintf and vsnwprintf. But only the newer
+ // distributions do.
+
+#if defined(__GNUC__)
+
+ inline int ssvsprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
+ {
+ return vsnprintf(pA, nCount, pFmtA, vl);
+ }
+ inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
+ {
+ return vswprintf(pW, nCount, pFmtW, vl);
+ }
+
+ // Microsofties can use
+#elif defined(_MSC_VER) && !defined(SS_ANSI)
+
+ inline int ssvsprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
+ {
+ return _vsnprintf(pA, nCount, pFmtA, vl);
+ }
+ inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
+ {
+ return _vsnwprintf(pW, nCount, pFmtW, vl);
+ }
+
+#elif defined (SS_DANGEROUS_FORMAT) // ignore buffer size parameter if needed?
+
+ inline int ssvsprintf(PSTR pA, size_t /*nCount*/, PCSTR pFmtA, va_list vl)
+ {
+ return vsprintf(pA, pFmtA, vl);
+ }
+
+ inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
+ {
+ // JMO: Some distributions of the "C" have a version of vswprintf that
+ // takes 3 arguments (e.g. Microsoft, Borland, GNU). Others have a
+ // version which takes 4 arguments (an extra "count" argument in the
+ // second position. The best stab I can take at this so far is that if
+ // you are NOT running with MS, Borland, or GNU, then I'll assume you
+ // have the version that takes 4 arguments.
+ //
+ // I'm sure that these checks don't catch every platform correctly so if
+ // you get compiler errors on one of the lines immediately below, it's
+ // probably because your implemntation takes a different number of
+ // arguments. You can comment out the offending line (and use the
+ // alternate version) or you can figure out what compiler flag to check
+ // and add that preprocessor check in. Regardless, if you get an error
+ // on these lines, I'd sure like to hear from you about it.
+ //
+ // Thanks to Ronny Schulz for the SGI-specific checks here.
+
+// #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)
+ #if !defined(_MSC_VER) \
+ && !defined (__BORLANDC__) \
+ && !defined(__GNUC__) \
+ && !defined(__sgi)
+
+ return vswprintf(pW, nCount, pFmtW, vl);
+
+ // suddenly with the current SGI 7.3 compiler there is no such function as
+ // vswprintf and the substitute needs explicit casts to compile
+
+ #elif defined(__sgi)
+
+ nCount;
+ return vsprintf( (char *)pW, (char *)pFmtW, vl);
+
+ #else
+
+ nCount;
+ return vswprintf(pW, pFmtW, vl);
+
+ #endif
+
+ }
+
+#endif
+
+ // GOT COMPILER PROBLEMS HERE?
+ // ---------------------------
+ // Does your compiler choke on one or more of the following 2 functions? It
+ // probably means that you don't have have either vsnprintf or vsnwprintf in
+ // your version of the CRT. This is understandable since neither is an ANSI
+ // "C" function. However it still leaves you in a dilemma. In order to make
+ // this code build, you're going to have to to use some non-length-checked
+ // formatting functions that every CRT has: vsprintf and vswprintf.
+ //
+ // This is very dangerous. With the proper erroneous (or malicious) code, it
+ // can lead to buffer overlows and crashing your PC. Use at your own risk
+ // In order to use them, just #define SS_DANGEROUS_FORMAT at the top of
+ // this file.
+ //
+ // Even THEN you might not be all the way home due to some non-conforming
+ // distributions. More on this in the comments below.
+
+ inline int ssnprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
+ {
+ #ifdef _MSC_VER
+ return _vsnprintf(pA, nCount, pFmtA, vl);
+ #else
+ return vsnprintf(pA, nCount, pFmtA, vl);
+ #endif
+ }
+ inline int ssnprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
+ {
+ #ifdef _MSC_VER
+ return _vsnwprintf(pW, nCount, pFmtW, vl);
+ #else
+ return vswprintf(pW, nCount, pFmtW, vl);
+ #endif
+ }
+
+
+
+
+// -----------------------------------------------------------------------------
+// ssload: Type safe, overloaded ::LoadString wrappers
+// There is no equivalent of these in non-Win32-specific builds. However, I'm
+// thinking that with the message facet, there might eventually be one
+// -----------------------------------------------------------------------------
+#if defined (SS_WIN32) && !defined(SS_ANSI)
+ inline int ssload(HMODULE hInst, UINT uId, PSTR pBuf, int nMax)
+ {
+ return ::LoadStringA(hInst, uId, pBuf, nMax);
+ }
+ inline int ssload(HMODULE hInst, UINT uId, PWSTR pBuf, int nMax)
+ {
+ return ::LoadStringW(hInst, uId, pBuf, nMax);
+ }
+#if defined ( _MSC_VER ) && ( _MSC_VER >= 1500 )
+ inline int ssload(HMODULE hInst, UINT uId, uint16_t *pBuf, int nMax)
+ {
+ return 0;
+ }
+ inline int ssload(HMODULE hInst, UINT uId, uint32_t *pBuf, int nMax)
+ {
+ return 0;
+ }
+#endif
+#endif
+
+
+// -----------------------------------------------------------------------------
+// sscoll/ssicoll: Collation wrappers
+// Note -- with MSVC I have reversed the arguments order here because the
+// functions appear to return the opposite of what they should
+// -----------------------------------------------------------------------------
+#ifndef SS_NO_LOCALE
+template <typename CT>
+inline int sscoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
+{
+ const std::collate<CT>& coll =
+ SS_USE_FACET(std::locale(), std::collate<CT>);
+
+ return coll.compare(sz2, sz2+nLen2, sz1, sz1+nLen1);
+}
+template <typename CT>
+inline int ssicoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
+{
+ const std::locale loc;
+ const std::collate<CT>& coll = SS_USE_FACET(loc, std::collate<CT>);
+
+ // Some implementations seem to have trouble using the collate<>
+ // facet typedefs so we'll just default to basic_string and hope
+ // that's what the collate facet uses (which it generally should)
+
+// std::collate<CT>::string_type s1(sz1);
+// std::collate<CT>::string_type s2(sz2);
+ const std::basic_string<CT> sEmpty;
+ std::basic_string<CT> s1(sz1 ? sz1 : sEmpty.c_str());
+ std::basic_string<CT> s2(sz2 ? sz2 : sEmpty.c_str());
+
+ sslwr(const_cast<CT*>(s1.c_str()), nLen1, loc);
+ sslwr(const_cast<CT*>(s2.c_str()), nLen2, loc);
+ return coll.compare(s2.c_str(), s2.c_str()+nLen2,
+ s1.c_str(), s1.c_str()+nLen1);
+}
+#endif
+
+
+// -----------------------------------------------------------------------------
+// ssfmtmsg: FormatMessage equivalents. Needed because I added a CString facade
+// Again -- no equivalent of these on non-Win32 builds but their might one day
+// be one if the message facet gets implemented
+// -----------------------------------------------------------------------------
+#if defined (SS_WIN32) && !defined(SS_ANSI)
+ inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
+ DWORD dwLangId, PSTR pBuf, DWORD nSize,
+ va_list* vlArgs)
+ {
+ return FormatMessageA(dwFlags, pSrc, dwMsgId, dwLangId,
+ pBuf, nSize,vlArgs);
+ }
+ inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
+ DWORD dwLangId, PWSTR pBuf, DWORD nSize,
+ va_list* vlArgs)
+ {
+ return FormatMessageW(dwFlags, pSrc, dwMsgId, dwLangId,
+ pBuf, nSize,vlArgs);
+ }
+#else
+#endif
+
+
+
+// FUNCTION: sscpy. Copies up to 'nMax' characters from pSrc to pDst.
+// -----------------------------------------------------------------------------
+// FUNCTION: sscpy
+// inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);
+// inline int sscpy(PUSTR pDst, PCSTR pSrc, int nMax=-1)
+// inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);
+// inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);
+// inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);
+//
+// DESCRIPTION:
+// This function is very much (but not exactly) like strcpy. These
+// overloads simplify copying one C-style string into another by allowing
+// the caller to specify two different types of strings if necessary.
+//
+// The strings must NOT overlap
+//
+// "Character" is expressed in terms of the destination string, not
+// the source. If no 'nMax' argument is supplied, then the number of
+// characters copied will be sslen(pSrc). A NULL terminator will
+// also be added so pDst must actually be big enough to hold nMax+1
+// characters. The return value is the number of characters copied,
+// not including the NULL terminator.
+//
+// PARAMETERS:
+// pSrc - the string to be copied FROM. May be a char based string, an
+// MBCS string (in Win32 builds) or a wide string (wchar_t).
+// pSrc - the string to be copied TO. Also may be either MBCS or wide
+// nMax - the maximum number of characters to be copied into szDest. Note
+// that this is expressed in whatever a "character" means to pDst.
+// If pDst is a wchar_t type string than this will be the maximum
+// number of wchar_ts that my be copied. The pDst string must be
+// large enough to hold least nMaxChars+1 characters.
+// If the caller supplies no argument for nMax this is a signal to
+// the routine to copy all the characters in pSrc, regardless of
+// how long it is.
+//
+// RETURN VALUE: none
+// -----------------------------------------------------------------------------
+
+template<typename CT1, typename CT2>
+inline int sscpycvt(CT1* pDst, const CT2* pSrc, int nMax)
+{
+ // Note -- we assume pDst is big enough to hold pSrc. If not, we're in
+ // big trouble. No bounds checking. Caveat emptor.
+
+ int nSrc = sslen(pSrc);
+
+ const CT1* szCvt = StdCodeCvt(pDst, nMax, pSrc, nSrc);
+
+ // If we're copying the same size characters, then all the "code convert"
+ // just did was basically memcpy so the #of characters copied is the same
+ // as the number requested. I should probably specialize this function
+ // template to achieve this purpose as it is silly to do a runtime check
+ // of a fact known at compile time. I'll get around to it.
+
+ return sslen(szCvt);
+}
+
+template<typename T>
+inline int sscpycvt(T* pDst, const T* pSrc, int nMax)
+{
+ int nCount = nMax;
+ for (; nCount > 0 && *pSrc; ++pSrc, ++pDst, --nCount)
+ std::basic_string<T>::traits_type::assign(*pDst, *pSrc);
+
+ *pDst = 0;
+ return nMax - nCount;
+}
+
+inline int sscpycvt(PWSTR pDst, PCSTR pSrc, int nMax)
+{
+ // Note -- we assume pDst is big enough to hold pSrc. If not, we're in
+ // big trouble. No bounds checking. Caveat emptor.
+
+ const PWSTR szCvt = StdCodeCvt(pDst, nMax, pSrc, nMax);
+ return sslen(szCvt);
+}
+
+template<typename CT1, typename CT2>
+inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax, int nLen)
+{
+ return sscpycvt(pDst, pSrc, SSMIN(nMax, nLen));
+}
+template<typename CT1, typename CT2>
+inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax)
+{
+ return sscpycvt(pDst, pSrc, SSMIN(nMax, sslen(pSrc)));
+}
+template<typename CT1, typename CT2>
+inline int sscpy(CT1* pDst, const CT2* pSrc)
+{
+ return sscpycvt(pDst, pSrc, sslen(pSrc));
+}
+template<typename CT1, typename CT2>
+inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc, int nMax)
+{
+ return sscpycvt(pDst, sSrc.c_str(), SSMIN(nMax, (int)sSrc.length()));
+}
+template<typename CT1, typename CT2>
+inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc)
+{
+ return sscpycvt(pDst, sSrc.c_str(), (int)sSrc.length());
+}
+
+#ifdef SS_INC_COMDEF
+ template<typename CT1>
+ inline int sscpy(CT1* pDst, const _bstr_t& bs, int nMax)
+ {
+ return sscpycvt(pDst, static_cast<PCOLESTR>(bs),
+ SSMIN(nMax, static_cast<int>(bs.length())));
+ }
+ template<typename CT1>
+ inline int sscpy(CT1* pDst, const _bstr_t& bs)
+ {
+ return sscpy(pDst, bs, static_cast<int>(bs.length()));
+ }
+#endif
+
+
+// -----------------------------------------------------------------------------
+// Functional objects for changing case. They also let you pass locales
+// -----------------------------------------------------------------------------
+
+#ifdef SS_NO_LOCALE
+ template<typename CT>
+ struct SSToUpper : public std::unary_function<CT, CT>
+ {
+ inline CT operator()(const CT& t) const
+ {
+ return sstoupper(t);
+ }
+ };
+ template<typename CT>
+ struct SSToLower : public std::unary_function<CT, CT>
+ {
+ inline CT operator()(const CT& t) const
+ {
+ return sstolower(t);
+ }
+ };
+#else
+ template<typename CT>
+ struct SSToUpper : public std::binary_function<CT, std::locale, CT>
+ {
+ inline CT operator()(const CT& t, const std::locale& loc) const
+ {
+ return sstoupper<CT>(t, loc);
+ }
+ };
+ template<typename CT>
+ struct SSToLower : public std::binary_function<CT, std::locale, CT>
+ {
+ inline CT operator()(const CT& t, const std::locale& loc) const
+ {
+ return sstolower<CT>(t, loc);
+ }
+ };
+#endif
+
+// This struct is used for TrimRight() and TrimLeft() function implementations.
+//template<typename CT>
+//struct NotSpace : public std::unary_function<CT, bool>
+//{
+// const std::locale& loc;
+// inline NotSpace(const std::locale& locArg) : loc(locArg) {}
+// inline bool operator() (CT t) { return !std::isspace(t, loc); }
+//};
+template<typename CT>
+struct NotSpace : public std::unary_function<CT, bool>
+{
+ // DINKUMWARE BUG:
+ // Note -- using std::isspace in a COM DLL gives us access violations
+ // because it causes the dynamic addition of a function to be called
+ // when the library shuts down. Unfortunately the list is maintained
+ // in DLL memory but the function is in static memory. So the COM DLL
+ // goes away along with the function that was supposed to be called,
+ // and then later when the DLL CRT shuts down it unloads the list and
+ // tries to call the long-gone function.
+ // This is DinkumWare's implementation problem. If you encounter this
+ // problem, you may replace the calls here with good old isspace() and
+ // iswspace() from the CRT unless they specify SS_ANSI
+
+#ifdef SS_NO_LOCALE
+
+ bool operator() (CT t) const { return !ssisspace(t); }
+
+#else
+ const std::locale loc;
+ NotSpace(const std::locale& locArg=std::locale()) : loc(locArg) {}
+ bool operator() (CT t) const { return !std::isspace(t, loc); }
+#endif
+};
+
+
+
+
+// Now we can define the template (finally!)
+// =============================================================================
+// TEMPLATE: CStdStr
+// template<typename CT> class CStdStr : public std::basic_string<CT>
+//
+// REMARKS:
+// This template derives from basic_string<CT> and adds some MFC CString-
+// like functionality
+//
+// Basically, this is my attempt to make Standard C++ library strings as
+// easy to use as the MFC CString class.
+//
+// Note that although this is a template, it makes the assumption that the
+// template argument (CT, the character type) is either char or wchar_t.
+// =============================================================================
+
+//#define CStdStr _SS // avoid compiler warning 4786
+
+// template<typename ARG> ARG& FmtArg(ARG& arg) { return arg; }
+// PCSTR FmtArg(const std::string& arg) { return arg.c_str(); }
+// PCWSTR FmtArg(const std::wstring& arg) { return arg.c_str(); }
+
+template<typename ARG>
+struct FmtArg
+{
+ explicit FmtArg(const ARG& arg) : a_(arg) {}
+ const ARG& operator()() const { return a_; }
+ const ARG& a_;
+private:
+ FmtArg& operator=(const FmtArg&) { return *this; }
+};
+
+template<typename CT>
+class CStdStr : public std::basic_string<CT>
+{
+ // Typedefs for shorter names. Using these names also appears to help
+ // us avoid some ambiguities that otherwise arise on some platforms
+
+ #define MYBASE std::basic_string<CT> // my base class
+ //typedef typename std::basic_string<CT> MYBASE; // my base class
+ typedef CStdStr<CT> MYTYPE; // myself
+ typedef typename MYBASE::const_pointer PCMYSTR; // PCSTR or PCWSTR
+ typedef typename MYBASE::pointer PMYSTR; // PSTR or PWSTR
+ typedef typename MYBASE::iterator MYITER; // my iterator type
+ typedef typename MYBASE::const_iterator MYCITER; // you get the idea...
+ typedef typename MYBASE::reverse_iterator MYRITER;
+ typedef typename MYBASE::size_type MYSIZE;
+ typedef typename MYBASE::value_type MYVAL;
+ typedef typename MYBASE::allocator_type MYALLOC;
+
+public:
+ // shorthand conversion from PCTSTR to string resource ID
+ #define SSRES(pctstr) LOWORD(reinterpret_cast<unsigned long>(pctstr))
+
+ bool TryLoad(const void* pT)
+ {
+ bool bLoaded = false;
+
+#if defined(SS_WIN32) && !defined(SS_ANSI)
+ if ( ( pT != NULL ) && SS_IS_INTRESOURCE(pT) )
+ {
+ UINT nId = LOWORD(reinterpret_cast<unsigned long>(pT));
+ if ( !LoadString(nId) )
+ {
+ TRACE(_T("Can't load string %u\n"), SSRES(pT));
+ }
+ bLoaded = true;
+ }
+#endif
+
+ return bLoaded;
+ }
+
+
+ // CStdStr inline constructors
+ CStdStr()
+ {
+ }
+
+ CStdStr(const MYTYPE& str) : MYBASE(SSREF(str))
+ {
+ }
+
+ CStdStr(const std::string& str)
+ {
+ ssasn(*this, SSREF(str));
+ }
+
+ CStdStr(const std::wstring& str)
+ {
+ ssasn(*this, SSREF(str));
+ }
+
+ CStdStr(PCMYSTR pT, MYSIZE n) : MYBASE(pT, n)
+ {
+ }
+
+#ifdef SS_UNSIGNED
+ CStdStr(PCUSTR pU)
+ {
+ *this = reinterpret_cast<PCSTR>(pU);
+ }
+#endif
+
+ CStdStr(PCSTR pA)
+ {
+ #ifdef SS_ANSI
+ *this = pA;
+ #else
+ if ( !TryLoad(pA) )
+ *this = pA;
+ #endif
+ }
+
+ CStdStr(PCWSTR pW)
+ {
+ #ifdef SS_ANSI
+ *this = pW;
+ #else
+ if ( !TryLoad(pW) )
+ *this = pW;
+ #endif
+ }
+
+ CStdStr(uint16_t* pW)
+ {
+ #ifdef SS_ANSI
+ *this = pW;
+ #else
+ if ( !TryLoad(pW) )
+ *this = pW;
+ #endif
+ }
+
+ CStdStr(uint32_t* pW)
+ {
+ #ifdef SS_ANSI
+ *this = pW;
+ #else
+ if ( !TryLoad(pW) )
+ *this = pW;
+ #endif
+ }
+
+ CStdStr(MYCITER first, MYCITER last)
+ : MYBASE(first, last)
+ {
+ }
+
+ CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC& al=MYALLOC())
+ : MYBASE(nSize, ch, al)
+ {
+ }
+
+ #ifdef SS_INC_COMDEF
+ CStdStr(const _bstr_t& bstr)
+ {
+ if ( bstr.length() > 0 )
+ this->append(static_cast<PCMYSTR>(bstr), bstr.length());
+ }
+ #endif
+
+ // CStdStr inline assignment operators -- the ssasn function now takes care
+ // of fixing the MSVC assignment bug (see knowledge base article Q172398).
+ MYTYPE& operator=(const MYTYPE& str)
+ {
+ ssasn(*this, str);
+ return *this;
+ }
+
+ MYTYPE& operator=(const std::string& str)
+ {
+ ssasn(*this, str);
+ return *this;
+ }
+
+ MYTYPE& operator=(const std::wstring& str)
+ {
+ ssasn(*this, str);
+ return *this;
+ }
+
+ MYTYPE& operator=(PCSTR pA)
+ {
+ ssasn(*this, pA);
+ return *this;
+ }
+
+ MYTYPE& operator=(PCWSTR pW)
+ {
+ ssasn(*this, pW);
+ return *this;
+ }
+
+#ifdef SS_UNSIGNED
+ MYTYPE& operator=(PCUSTR pU)
+ {
+ ssasn(*this, reinterpret_cast<PCSTR>(pU));
+ return *this;
+ }
+#endif
+
+ MYTYPE& operator=(uint16_t* pA)
+ {
+ ssasn(*this, pA);
+ return *this;
+ }
+
+ MYTYPE& operator=(uint32_t* pA)
+ {
+ ssasn(*this, pA);
+ return *this;
+ }
+
+ MYTYPE& operator=(CT t)
+ {
+ Q172398(*this);
+ this->assign(1, t);
+ return *this;
+ }
+
+ #ifdef SS_INC_COMDEF
+ MYTYPE& operator=(const _bstr_t& bstr)
+ {
+ if ( bstr.length() > 0 )
+ {
+ this->assign(static_cast<PCMYSTR>(bstr), bstr.length());
+ return *this;
+ }
+ else
+ {
+ this->erase();
+ return *this;
+ }
+ }
+ #endif
+
+
+ // Overloads also needed to fix the MSVC assignment bug (KB: Q172398)
+ // *** Thanks to Pete The Plumber for catching this one ***
+ // They also are compiled if you have explicitly turned off refcounting
+ #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT)
+
+ MYTYPE& assign(const MYTYPE& str)
+ {
+ Q172398(*this);
+ sscpy(GetBuffer(str.size()+1), SSREF(str));
+ this->ReleaseBuffer(str.size());
+ return *this;
+ }
+
+ MYTYPE& assign(const MYTYPE& str, MYSIZE nStart, MYSIZE nChars)
+ {
+ // This overload of basic_string::assign is supposed to assign up to
+ // <nChars> or the NULL terminator, whichever comes first. Since we
+ // are about to call a less forgiving overload (in which <nChars>
+ // must be a valid length), we must adjust the length here to a safe
+ // value. Thanks to Ullrich Poll�hne for catching this bug
+
+ nChars = SSMIN(nChars, str.length() - nStart);
+ MYTYPE strTemp(str.c_str()+nStart, nChars);
+ Q172398(*this);
+ this->assign(strTemp);
+ return *this;
+ }
+
+ MYTYPE& assign(const MYBASE& str)
+ {
+ ssasn(*this, str);
+ return *this;
+ }
+
+ MYTYPE& assign(const MYBASE& str, MYSIZE nStart, MYSIZE nChars)
+ {
+ // This overload of basic_string::assign is supposed to assign up to
+ // <nChars> or the NULL terminator, whichever comes first. Since we
+ // are about to call a less forgiving overload (in which <nChars>
+ // must be a valid length), we must adjust the length here to a safe
+ // value. Thanks to Ullrich Poll�hne for catching this bug
+
+ nChars = SSMIN(nChars, str.length() - nStart);
+
+ // Watch out for assignment to self
+
+ if ( this == &str )
+ {
+ MYTYPE strTemp(str.c_str() + nStart, nChars);
+ static_cast<MYBASE*>(this)->assign(strTemp);
+ }
+ else
+ {
+ Q172398(*this);
+ static_cast<MYBASE*>(this)->assign(str.c_str()+nStart, nChars);
+ }
+ return *this;
+ }
+
+ MYTYPE& assign(const CT* pC, MYSIZE nChars)
+ {
+ // Q172398 only fix -- erase before assigning, but not if we're
+ // assigning from our own buffer
+
+ #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
+ if ( !this->empty() &&
+ ( pC < this->data() || pC > this->data() + this->capacity() ) )
+ {
+ this->erase();
+ }
+ #endif
+ Q172398(*this);
+ static_cast<MYBASE*>(this)->assign(pC, nChars);
+ return *this;
+ }
+
+ MYTYPE& assign(MYSIZE nChars, MYVAL val)
+ {
+ Q172398(*this);
+ static_cast<MYBASE*>(this)->assign(nChars, val);
+ return *this;
+ }
+
+ MYTYPE& assign(const CT* pT)
+ {
+ return this->assign(pT, MYBASE::traits_type::length(pT));
+ }
+
+ MYTYPE& assign(MYCITER iterFirst, MYCITER iterLast)
+ {
+ #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
+ // Q172398 fix. don't call erase() if we're assigning from ourself
+ if ( iterFirst < this->begin() ||
+ iterFirst > this->begin() + this->size() )
+ {
+ this->erase()
+ }
+ #endif
+ this->replace(this->begin(), this->end(), iterFirst, iterLast);
+ return *this;
+ }
+ #endif
+
+
+ // -------------------------------------------------------------------------
+ // CStdStr inline concatenation.
+ // -------------------------------------------------------------------------
+ MYTYPE& operator+=(const MYTYPE& str)
+ {
+ ssadd(*this, str);
+ return *this;
+ }
+
+ MYTYPE& operator+=(const std::string& str)
+ {
+ ssadd(*this, str);
+ return *this;
+ }
+
+ MYTYPE& operator+=(const std::wstring& str)
+ {
+ ssadd(*this, str);
+ return *this;
+ }
+
+ MYTYPE& operator+=(PCSTR pA)
+ {
+ ssadd(*this, pA);
+ return *this;
+ }
+
+ MYTYPE& operator+=(PCWSTR pW)
+ {
+ ssadd(*this, pW);
+ return *this;
+ }
+
+ MYTYPE& operator+=(uint16_t* pW)
+ {
+ ssadd(*this, pW);
+ return *this;
+ }
+
+ MYTYPE& operator+=(uint32_t* pW)
+ {
+ ssadd(*this, pW);
+ return *this;
+ }
+
+ MYTYPE& operator+=(CT t)
+ {
+ this->append(1, t);
+ return *this;
+ }
+ #ifdef SS_INC_COMDEF // if we have _bstr_t, define a += for it too.
+ MYTYPE& operator+=(const _bstr_t& bstr)
+ {
+ return this->operator+=(static_cast<PCMYSTR>(bstr));
+ }
+ #endif
+
+
+ // -------------------------------------------------------------------------
+ // Case changing functions
+ // -------------------------------------------------------------------------
+
+ MYTYPE& ToUpper(const std::locale& loc=std::locale())
+ {
+ // Note -- if there are any MBCS character sets in which the lowercase
+ // form a character takes up a different number of bytes than the
+ // uppercase form, this would probably not work...
+
+ std::transform(this->begin(),
+ this->end(),
+ this->begin(),
+#ifdef SS_NO_LOCALE
+ SSToUpper<CT>());
+#else
+ std::bind2nd(SSToUpper<CT>(), loc));
+#endif
+
+ // ...but if it were, this would probably work better. Also, this way
+ // seems to be a bit faster when anything other then the "C" locale is
+ // used...
+
+// if ( !empty() )
+// {
+// ssupr(this->GetBuf(), this->size(), loc);
+// this->RelBuf();
+// }
+
+ return *this;
+ }
+
+ MYTYPE& ToLower(const std::locale& loc=std::locale())
+ {
+ // Note -- if there are any MBCS character sets in which the lowercase
+ // form a character takes up a different number of bytes than the
+ // uppercase form, this would probably not work...
+
+ std::transform(this->begin(),
+ this->end(),
+ this->begin(),
+#ifdef SS_NO_LOCALE
+ SSToLower<CT>());
+#else
+ std::bind2nd(SSToLower<CT>(), loc));
+#endif
+
+ // ...but if it were, this would probably work better. Also, this way
+ // seems to be a bit faster when anything other then the "C" locale is
+ // used...
+
+// if ( !empty() )
+// {
+// sslwr(this->GetBuf(), this->size(), loc);
+// this->RelBuf();
+// }
+ return *this;
+ }
+
+
+ MYTYPE& Normalize()
+ {
+ return Trim().ToLower();
+ }
+
+
+ // -------------------------------------------------------------------------
+ // CStdStr -- Direct access to character buffer. In the MS' implementation,
+ // the at() function that we use here also calls _Freeze() providing us some
+ // protection from multithreading problems associated with ref-counting.
+ // In VC 7 and later, of course, the ref-counting stuff is gone.
+ // -------------------------------------------------------------------------
+
+ CT* GetBuf(int nMinLen=-1)
+ {
+ if ( static_cast<int>(this->size()) < nMinLen )
+ this->resize(static_cast<MYSIZE>(nMinLen));
+
+ return this->empty() ? const_cast<CT*>(this->data()) : &(this->at(0));
+ }
+
+ CT* SetBuf(int nLen)
+ {
+ nLen = ( nLen > 0 ? nLen : 0 );
+ if ( this->capacity() < 1 && nLen == 0 )
+ this->resize(1);
+
+ this->resize(static_cast<MYSIZE>(nLen));
+ return const_cast<CT*>(this->data());
+ }
+ void RelBuf(int nNewLen=-1)
+ {
+ this->resize(static_cast<MYSIZE>(nNewLen > -1 ? nNewLen :
+ sslen(this->c_str())));
+ }
+
+ void BufferRel() { RelBuf(); } // backwards compatability
+ CT* Buffer() { return GetBuf(); } // backwards compatability
+ CT* BufferSet(int nLen) { return SetBuf(nLen);}// backwards compatability
+
+ bool Equals(const CT* pT, bool bUseCase=false) const
+ {
+ return 0 == (bUseCase ? this->compare(pT) : ssicmp(this->c_str(), pT));
+ }
+
+ // -------------------------------------------------------------------------
+ // FUNCTION: CStdStr::Load
+ // REMARKS:
+ // Loads string from resource specified by nID
+ //
+ // PARAMETERS:
+ // nID - resource Identifier. Purely a Win32 thing in this case
+ //
+ // RETURN VALUE:
+ // true if successful, false otherwise
+ // -------------------------------------------------------------------------
+
+#ifndef SS_ANSI
+
+ bool Load(UINT nId, HMODULE hModule=NULL)
+ {
+ bool bLoaded = false; // set to true of we succeed.
+
+ #ifdef _MFC_VER // When in Rome (or MFC land)...
+
+ // If they gave a resource handle, use it. Note - this is archaic
+ // and not really what I would recommend. But then again, in MFC
+ // land, you ought to be using CString for resources anyway since
+ // it walks the resource chain for you.
+
+ HMODULE hModuleOld = NULL;
+
+ if ( NULL != hModule )
+ {
+ hModuleOld = AfxGetResourceHandle();
+ AfxSetResourceHandle(hModule);
+ }
+
+ // ...load the string
+
+ CString strRes;
+ bLoaded = FALSE != strRes.LoadString(nId);
+
+ // ...and if we set the resource handle, restore it.
+
+ if ( NULL != hModuleOld )
+ AfxSetResourceHandle(hModule);
+
+ if ( bLoaded )
+ *this = strRes;
+
+ #else // otherwise make our own hackneyed version of CString's Load
+
+ // Get the resource name and module handle
+
+ if ( NULL == hModule )
+ hModule = GetResourceHandle();
+
+ PCTSTR szName = MAKEINTRESOURCE((nId>>4)+1); // lifted
+ DWORD dwSize = 0;
+
+ // No sense continuing if we can't find the resource
+
+ HRSRC hrsrc = ::FindResource(hModule, szName, RT_STRING);
+
+ if ( NULL == hrsrc )
+ {
+ TRACE(_T("Cannot find resource %d: 0x%X"), nId, ::GetLastError());
+ }
+ else if ( 0 == (dwSize = ::SizeofResource(hModule, hrsrc) / sizeof(CT)))
+ {
+ TRACE(_T("Cant get size of resource %d 0x%X\n"),nId,GetLastError());
+ }
+ else
+ {
+ bLoaded = 0 != ssload(hModule, nId, GetBuf(dwSize), dwSize);
+ ReleaseBuffer();
+ }
+
+ #endif // #ifdef _MFC_VER
+
+ if ( !bLoaded )
+ TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());
+
+ return bLoaded;
+ }
+
+#endif // #ifdef SS_ANSI
+
+ // -------------------------------------------------------------------------
+ // FUNCTION: CStdStr::Format
+ // void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)
+ // void _cdecl Format(PCSTR szFormat);
+ //
+ // DESCRIPTION:
+ // This function does sprintf/wsprintf style formatting on CStdStringA
+ // objects. It looks a lot like MFC's CString::Format. Some people
+ // might even call this identical. Fortunately, these people are now
+ // dead... heh heh.
+ //
+ // PARAMETERS:
+ // nId - ID of string resource holding the format string
+ // szFormat - a PCSTR holding the format specifiers
+ // argList - a va_list holding the arguments for the format specifiers.
+ //
+ // RETURN VALUE: None.
+ // -------------------------------------------------------------------------
+ // formatting (using wsprintf style formatting)
+
+ // If they want a Format() function that safely handles string objects
+ // without casting
+
+#ifdef SS_SAFE_FORMAT
+
+ // Question: Joe, you wacky coder you, why do you have so many overloads
+ // of the Format() function
+ // Answer: One reason only - CString compatability. In short, by making
+ // the Format() function a template this way, I can do strong typing
+ // and allow people to pass CStdString arguments as fillers for
+ // "%s" format specifiers without crashing their program! The downside
+ // is that I need to overload on the number of arguments. If you are
+ // passing more arguments than I have listed below in any of my
+ // overloads, just add another one.
+ //
+ // Yes, yes, this is really ugly. In essence what I am doing here is
+ // protecting people from a bad (and incorrect) programming practice
+ // that they should not be doing anyway. I am protecting them from
+ // themselves. Why am I doing this? Well, if you had any idea the
+ // number of times I've been emailed by people about this
+ // "incompatability" in my code, you wouldn't ask.
+
+ void Fmt(const CT* szFmt, ...)
+ {
+ va_list argList;
+ va_start(argList, szFmt);
+ FormatV(szFmt, argList);
+ va_end(argList);
+ }
+
+#ifndef SS_ANSI
+
+ void Format(UINT nId)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ this->swap(strFmt);
+ }
+ template<class A1>
+ void Format(UINT nId, const A1& v)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ Fmt(strFmt, FmtArg<A1>(v)());
+ }
+ template<class A1, class A2>
+ void Format(UINT nId, const A1& v1, const A2& v2)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)());
+ }
+ template<class A1, class A2, class A3>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)());
+ }
+ }
+ template<class A1, class A2, class A3, class A4>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)());
+ }
+ }
+ template<class A1, class A2, class A3, class A4, class A5>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)());
+ }
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(),FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)());
+ }
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(),FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)());
+ }
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)());
+ }
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)());
+ }
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(), FmtArg<A10>(v10)());
+ }
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10, class A11>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10, const A11& v11)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(),FmtArg<A10>(v10)(),FmtArg<A11>(v11)());
+ }
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10, class A11, class A12>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10, const A11& v11,
+ const A12& v12)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
+ FmtArg<A12>(v12)());
+ }
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10, class A11, class A12,
+ class A13>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10, const A11& v11,
+ const A12& v12, const A13& v13)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
+ FmtArg<A12>(v12)(), FmtArg<A13>(v13)());
+ }
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10, class A11, class A12,
+ class A13, class A14>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10, const A11& v11,
+ const A12& v12, const A13& v13, const A14& v14)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
+ FmtArg<A12>(v12)(), FmtArg<A13>(v13)(),FmtArg<A14>(v14)());
+ }
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10, class A11, class A12,
+ class A13, class A14, class A15>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10, const A11& v11,
+ const A12& v12, const A13& v13, const A14& v14, const A15& v15)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
+ FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
+ FmtArg<A15>(v15)());
+ }
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10, class A11, class A12,
+ class A13, class A14, class A15, class A16>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10, const A11& v11,
+ const A12& v12, const A13& v13, const A14& v14, const A15& v15,
+ const A16& v16)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
+ FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
+ FmtArg<A15>(v15)(), FmtArg<A16>(v16)());
+ }
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10, class A11, class A12,
+ class A13, class A14, class A15, class A16, class A17>
+ void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10, const A11& v11,
+ const A12& v12, const A13& v13, const A14& v14, const A15& v15,
+ const A16& v16, const A17& v17)
+ {
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ {
+ Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
+ FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
+ FmtArg<A15>(v15)(),FmtArg<A16>(v16)(),FmtArg<A17>(v17)());
+ }
+ }
+
+#endif // #ifndef SS_ANSI
+
+ // ...now the other overload of Format: the one that takes a string literal
+
+ void Format(const CT* szFmt)
+ {
+ *this = szFmt;
+ }
+ template<class A1>
+ void Format(const CT* szFmt, const A1& v)
+ {
+ Fmt(szFmt, FmtArg<A1>(v)());
+ }
+ template<class A1, class A2>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)());
+ }
+ template<class A1, class A2, class A3>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)());
+ }
+ template<class A1, class A2, class A3, class A4>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)());
+ }
+ template<class A1, class A2, class A3, class A4, class A5>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)());
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)());
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)());
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)());
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)());
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(), FmtArg<A10>(v10)());
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10, class A11>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10, const A11& v11)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(),FmtArg<A10>(v10)(),FmtArg<A11>(v11)());
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10, class A11, class A12>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10, const A11& v11,
+ const A12& v12)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
+ FmtArg<A12>(v12)());
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10, class A11, class A12,
+ class A13>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10, const A11& v11,
+ const A12& v12, const A13& v13)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
+ FmtArg<A12>(v12)(), FmtArg<A13>(v13)());
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10, class A11, class A12,
+ class A13, class A14>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10, const A11& v11,
+ const A12& v12, const A13& v13, const A14& v14)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
+ FmtArg<A12>(v12)(), FmtArg<A13>(v13)(),FmtArg<A14>(v14)());
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10, class A11, class A12,
+ class A13, class A14, class A15>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10, const A11& v11,
+ const A12& v12, const A13& v13, const A14& v14, const A15& v15)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
+ FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
+ FmtArg<A15>(v15)());
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10, class A11, class A12,
+ class A13, class A14, class A15, class A16>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10, const A11& v11,
+ const A12& v12, const A13& v13, const A14& v14, const A15& v15,
+ const A16& v16)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
+ FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
+ FmtArg<A15>(v15)(), FmtArg<A16>(v16)());
+ }
+ template<class A1, class A2, class A3, class A4, class A5, class A6,
+ class A7, class A8, class A9, class A10, class A11, class A12,
+ class A13, class A14, class A15, class A16, class A17>
+ void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
+ const A4& v4, const A5& v5, const A6& v6, const A7& v7,
+ const A8& v8, const A9& v9, const A10& v10, const A11& v11,
+ const A12& v12, const A13& v13, const A14& v14, const A15& v15,
+ const A16& v16, const A17& v17)
+ {
+ Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
+ FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
+ FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
+ FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
+ FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
+ FmtArg<A15>(v15)(),FmtArg<A16>(v16)(),FmtArg<A17>(v17)());
+ }
+
+#else // #ifdef SS_SAFE_FORMAT
+
+
+#ifndef SS_ANSI
+
+ void Format(UINT nId, ...)
+ {
+ va_list argList;
+ va_start(argList, nId);
+
+ MYTYPE strFmt;
+ if ( strFmt.Load(nId) )
+ FormatV(strFmt, argList);
+
+ va_end(argList);
+ }
+
+#endif // #ifdef SS_ANSI
+
+ void Format(const CT* szFmt, ...)
+ {
+ va_list argList;
+ va_start(argList, szFmt);
+ FormatV(szFmt, argList);
+ va_end(argList);
+ }
+
+#endif // #ifdef SS_SAFE_FORMAT
+
+ void AppendFormat(const CT* szFmt, ...)
+ {
+ va_list argList;
+ va_start(argList, szFmt);
+ AppendFormatV(szFmt, argList);
+ va_end(argList);
+ }
+
+ #define MAX_FMT_TRIES 5 // #of times we try
+ #define FMT_BLOCK_SIZE 2048 // # of bytes to increment per try
+ #define BUFSIZE_1ST 256
+ #define BUFSIZE_2ND 512
+ #define STD_BUF_SIZE 1024
+
+ // an efficient way to add formatted characters to the string. You may only
+ // add up to STD_BUF_SIZE characters at a time, though
+ void AppendFormatV(const CT* szFmt, va_list argList)
+ {
+ CT szBuf[STD_BUF_SIZE];
+ int nLen = ssnprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);
+
+ if ( 0 < nLen )
+ this->append(szBuf, nLen);
+ }
+
+ // -------------------------------------------------------------------------
+ // FUNCTION: FormatV
+ // void FormatV(PCSTR szFormat, va_list, argList);
+ //
+ // DESCRIPTION:
+ // This function formats the string with sprintf style format-specs.
+ // It makes a general guess at required buffer size and then tries
+ // successively larger buffers until it finds one big enough or a
+ // threshold (MAX_FMT_TRIES) is exceeded.
+ //
+ // PARAMETERS:
+ // szFormat - a PCSTR holding the format of the output
+ // argList - a Microsoft specific va_list for variable argument lists
+ //
+ // RETURN VALUE:
+ // -------------------------------------------------------------------------
+
+ // NOTE: Changed by JM to actually function under non-win32,
+ // and to remove the upper limit on size.
+ void FormatV(const CT* szFormat, va_list argList)
+ {
+ // try and grab a sufficient buffersize
+ int nChars = FMT_BLOCK_SIZE;
+ va_list argCopy;
+
+ CT *p = reinterpret_cast<CT*>(malloc(sizeof(CT)*nChars));
+ if (!p) return;
+
+ while (1)
+ {
+ va_copy(argCopy, argList);
+
+ int nActual = ssvsprintf(p, nChars, szFormat, argCopy);
+ /* If that worked, return the string. */
+ if (nActual > -1 && nActual < nChars)
+ { /* make sure it's NULL terminated */
+ p[nActual] = '\0';
+ this->assign(p, nActual);
+ free(p);
+ va_end(argCopy);
+ return;
+ }
+ /* Else try again with more space. */
+ if (nActual > -1) /* glibc 2.1 */
+ nChars = nActual + 1; /* precisely what is needed */
+ else /* glibc 2.0 */
+ nChars *= 2; /* twice the old size */
+
+ CT *np = reinterpret_cast<CT*>(realloc(p, sizeof(CT)*nChars));
+ if (np == NULL)
+ {
+ free(p);
+ va_end(argCopy);
+ return; // failed :(
+ }
+ p = np;
+ va_end(argCopy);
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // CString Facade Functions:
+ //
+ // The following methods are intended to allow you to use this class as a
+ // near drop-in replacement for CString.
+ // -------------------------------------------------------------------------
+ #ifdef SS_WIN32
+ BSTR AllocSysString() const
+ {
+ ostring os;
+ ssasn(os, *this);
+ return ::SysAllocString(os.c_str());
+ }
+ #endif
+
+#ifndef SS_NO_LOCALE
+ int Collate(PCMYSTR szThat) const
+ {
+ return sscoll(this->c_str(), this->length(), szThat, sslen(szThat));
+ }
+
+ int CollateNoCase(PCMYSTR szThat) const
+ {
+ return ssicoll(this->c_str(), this->length(), szThat, sslen(szThat));
+ }
+#endif
+ int Compare(PCMYSTR szThat) const
+ {
+ return this->compare(szThat);
+ }
+
+ int CompareNoCase(PCMYSTR szThat) const
+ {
+ return ssicmp(this->c_str(), szThat);
+ }
+
+ int Delete(int nIdx, int nCount=1)
+ {
+ if ( nIdx < 0 )
+ nIdx = 0;
+
+ if ( nIdx < this->GetLength() )
+ this->erase(static_cast<MYSIZE>(nIdx), static_cast<MYSIZE>(nCount));
+
+ return GetLength();
+ }
+
+ void Empty()
+ {
+ this->erase();
+ }
+
+ int Find(CT ch) const
+ {
+ MYSIZE nIdx = this->find_first_of(ch);
+ return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
+ }
+
+ int Find(PCMYSTR szSub) const
+ {
+ MYSIZE nIdx = this->find(szSub);
+ return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
+ }
+
+ int Find(CT ch, int nStart) const
+ {
+ // CString::Find docs say add 1 to nStart when it's not zero
+ // CString::Find code doesn't do that however. We'll stick
+ // with what the code does
+
+ MYSIZE nIdx = this->find_first_of(ch, static_cast<MYSIZE>(nStart));
+ return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
+ }
+
+ int Find(PCMYSTR szSub, int nStart) const
+ {
+ // CString::Find docs say add 1 to nStart when it's not zero
+ // CString::Find code doesn't do that however. We'll stick
+ // with what the code does
+
+ MYSIZE nIdx = this->find(szSub, static_cast<MYSIZE>(nStart));
+ return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
+ }
+
+ int FindOneOf(PCMYSTR szCharSet) const
+ {
+ MYSIZE nIdx = this->find_first_of(szCharSet);
+ return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
+ }
+
+#ifndef SS_ANSI
+ void FormatMessage(PCMYSTR szFormat, ...) throw(std::exception)
+ {
+ va_list argList;
+ va_start(argList, szFormat);
+ PMYSTR szTemp;
+ if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ szFormat, 0, 0,
+ reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
+ szTemp == 0 )
+ {
+ throw std::runtime_error("out of memory");
+ }
+ *this = szTemp;
+ LocalFree(szTemp);
+ va_end(argList);
+ }
+
+ void FormatMessage(UINT nFormatId, ...) throw(std::exception)
+ {
+ MYTYPE sFormat;
+ VERIFY(sFormat.LoadString(nFormatId));
+ va_list argList;
+ va_start(argList, nFormatId);
+ PMYSTR szTemp;
+ if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ sFormat, 0, 0,
+ reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
+ szTemp == 0)
+ {
+ throw std::runtime_error("out of memory");
+ }
+ *this = szTemp;
+ LocalFree(szTemp);
+ va_end(argList);
+ }
+#endif
+
+ // GetAllocLength -- an MSVC7 function but it costs us nothing to add it.
+
+ int GetAllocLength()
+ {
+ return static_cast<int>(this->capacity());
+ }
+
+ // -------------------------------------------------------------------------
+ // GetXXXX -- Direct access to character buffer
+ // -------------------------------------------------------------------------
+ CT GetAt(int nIdx) const
+ {
+ return this->at(static_cast<MYSIZE>(nIdx));
+ }
+
+ CT* GetBuffer(int nMinLen=-1)
+ {
+ return GetBuf(nMinLen);
+ }
+
+ CT* GetBufferSetLength(int nLen)
+ {
+ return BufferSet(nLen);
+ }
+
+ // GetLength() -- MFC docs say this is the # of BYTES but
+ // in truth it is the number of CHARACTERs (chars or wchar_ts)
+ int GetLength() const
+ {
+ return static_cast<int>(this->length());
+ }
+
+ int Insert(int nIdx, CT ch)
+ {
+ if ( static_cast<MYSIZE>(nIdx) > this->size()-1 )
+ this->append(1, ch);
+ else
+ this->insert(static_cast<MYSIZE>(nIdx), 1, ch);
+
+ return GetLength();
+ }
+ int Insert(int nIdx, PCMYSTR sz)
+ {
+ if ( static_cast<MYSIZE>(nIdx) >= this->size() )
+ this->append(sz, static_cast<MYSIZE>(sslen(sz)));
+ else
+ this->insert(static_cast<MYSIZE>(nIdx), sz);
+
+ return GetLength();
+ }
+
+ bool IsEmpty() const
+ {
+ return this->empty();
+ }
+
+ MYTYPE Left(int nCount) const
+ {
+ // Range check the count.
+
+ nCount = SSMAX(0, SSMIN(nCount, static_cast<int>(this->size())));
+ return this->substr(0, static_cast<MYSIZE>(nCount));
+ }
+
+#ifndef SS_ANSI
+ bool LoadString(UINT nId)
+ {
+ return this->Load(nId);
+ }
+#endif
+
+ void MakeLower()
+ {
+ ToLower();
+ }
+
+ void MakeReverse()
+ {
+ std::reverse(this->begin(), this->end());
+ }
+
+ void MakeUpper()
+ {
+ ToUpper();
+ }
+
+ MYTYPE Mid(int nFirst) const
+ {
+ return Mid(nFirst, this->GetLength()-nFirst);
+ }
+
+ MYTYPE Mid(int nFirst, int nCount) const
+ {
+ // CString does range checking here. Since we're trying to emulate it,
+ // we must check too.
+
+ if ( nFirst < 0 )
+ nFirst = 0;
+ if ( nCount < 0 )
+ nCount = 0;
+
+ int nSize = static_cast<int>(this->size());
+
+ if ( nFirst + nCount > nSize )
+ nCount = nSize - nFirst;
+
+ if ( nFirst > nSize )
+ return MYTYPE();
+
+ ASSERT(nFirst >= 0);
+ ASSERT(nFirst + nCount <= nSize);
+
+ return this->substr(static_cast<MYSIZE>(nFirst),
+ static_cast<MYSIZE>(nCount));
+ }
+
+ void ReleaseBuffer(int nNewLen=-1)
+ {
+ RelBuf(nNewLen);
+ }
+
+ int Remove(CT ch)
+ {
+ MYSIZE nIdx = 0;
+ int nRemoved = 0;
+ while ( (nIdx=this->find_first_of(ch)) != MYBASE::npos )
+ {
+ this->erase(nIdx, 1);
+ nRemoved++;
+ }
+ return nRemoved;
+ }
+
+ int Replace(CT chOld, CT chNew)
+ {
+ int nReplaced = 0;
+
+ for ( MYITER iter=this->begin(); iter != this->end(); iter++ )
+ {
+ if ( *iter == chOld )
+ {
+ *iter = chNew;
+ nReplaced++;
+ }
+ }
+
+ return nReplaced;
+ }
+
+ int Replace(PCMYSTR szOld, PCMYSTR szNew)
+ {
+ int nReplaced = 0;
+ MYSIZE nIdx = 0;
+ MYSIZE nOldLen = sslen(szOld);
+
+ if ( 0 != nOldLen )
+ {
+ // If the replacement string is longer than the one it replaces, this
+ // string is going to have to grow in size, Figure out how much
+ // and grow it all the way now, rather than incrementally
+
+ MYSIZE nNewLen = sslen(szNew);
+ if ( nNewLen > nOldLen )
+ {
+ int nFound = 0;
+ while ( nIdx < this->length() &&
+ (nIdx=this->find(szOld, nIdx)) != MYBASE::npos )
+ {
+ nFound++;
+ nIdx += nOldLen;
+ }
+ this->reserve(this->size() + nFound * (nNewLen - nOldLen));
+ }
+
+
+ static const CT ch = CT(0);
+ PCMYSTR szRealNew = szNew == 0 ? &ch : szNew;
+ nIdx = 0;
+
+ while ( nIdx < this->length() &&
+ (nIdx=this->find(szOld, nIdx)) != MYBASE::npos )
+ {
+ this->replace(this->begin()+nIdx, this->begin()+nIdx+nOldLen,
+ szRealNew);
+
+ nReplaced++;
+ nIdx += nNewLen;
+ }
+ }
+
+ return nReplaced;
+ }
+
+ int ReverseFind(CT ch) const
+ {
+ MYSIZE nIdx = this->find_last_of(ch);
+ return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
+ }
+
+ // ReverseFind overload that's not in CString but might be useful
+ int ReverseFind(PCMYSTR szFind, MYSIZE pos=MYBASE::npos) const
+ {
+ //yuvalt - this does not compile with g++ since MYTTYPE() is different type
+ //MYSIZE nIdx = this->rfind(0 == szFind ? MYTYPE() : szFind, pos);
+ MYSIZE nIdx = this->rfind(0 == szFind ? "" : szFind, pos);
+ return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
+ }
+
+ MYTYPE Right(int nCount) const
+ {
+ // Range check the count.
+
+ nCount = SSMAX(0, SSMIN(nCount, static_cast<int>(this->size())));
+ return this->substr(this->size()-static_cast<MYSIZE>(nCount));
+ }
+
+ void SetAt(int nIndex, CT ch)
+ {
+ ASSERT(this->size() > static_cast<MYSIZE>(nIndex));
+ this->at(static_cast<MYSIZE>(nIndex)) = ch;
+ }
+
+#ifndef SS_ANSI
+ BSTR SetSysString(BSTR* pbstr) const
+ {
+ ostring os;
+ ssasn(os, *this);
+ if ( !::SysReAllocStringLen(pbstr, os.c_str(), os.length()) )
+ throw std::runtime_error("out of memory");
+
+ ASSERT(*pbstr != 0);
+ return *pbstr;
+ }
+#endif
+
+ MYTYPE SpanExcluding(PCMYSTR szCharSet) const
+ {
+ MYSIZE pos = this->find_first_of(szCharSet);
+ return pos == MYBASE::npos ? *this : Left(pos);
+ }
+
+ MYTYPE SpanIncluding(PCMYSTR szCharSet) const
+ {
+ MYSIZE pos = this->find_first_not_of(szCharSet);
+ return pos == MYBASE::npos ? *this : Left(pos);
+ }
+
+#if defined SS_WIN32 && !defined(UNICODE) && !defined(SS_ANSI)
+
+ // CString's OemToAnsi and AnsiToOem functions are available only in
+ // Unicode builds. However since we're a template we also need a
+ // runtime check of CT and a reinterpret_cast to account for the fact
+ // that CStdStringW gets instantiated even in non-Unicode builds.
+
+ void AnsiToOem()
+ {
+ if ( sizeof(CT) == sizeof(char) && !empty() )
+ {
+ ::CharToOem(reinterpret_cast<PCSTR>(this->c_str()),
+ reinterpret_cast<PSTR>(GetBuf()));
+ }
+ else
+ {
+ ASSERT(false);
+ }
+ }
+
+ void OemToAnsi()
+ {
+ if ( sizeof(CT) == sizeof(char) && !empty() )
+ {
+ ::OemToChar(reinterpret_cast<PCSTR>(this->c_str()),
+ reinterpret_cast<PSTR>(GetBuf()));
+ }
+ else
+ {
+ ASSERT(false);
+ }
+ }
+
+#endif
+
+
+ // -------------------------------------------------------------------------
+ // Trim and its variants
+ // -------------------------------------------------------------------------
+ MYTYPE& Trim()
+ {
+ return TrimLeft().TrimRight();
+ }
+
+ MYTYPE& TrimLeft()
+ {
+ this->erase(this->begin(),
+ std::find_if(this->begin(), this->end(), NotSpace<CT>()));
+
+ return *this;
+ }
+
+ MYTYPE& TrimLeft(CT tTrim)
+ {
+ this->erase(0, this->find_first_not_of(tTrim));
+ return *this;
+ }
+
+ MYTYPE& TrimLeft(PCMYSTR szTrimChars)
+ {
+ this->erase(0, this->find_first_not_of(szTrimChars));
+ return *this;
+ }
+
+ MYTYPE& TrimRight()
+ {
+ // NOTE: When comparing reverse_iterators here (MYRITER), I avoid using
+ // operator!=. This is because namespace rel_ops also has a template
+ // operator!= which conflicts with the global operator!= already defined
+ // for reverse_iterator in the header <utility>.
+ // Thanks to John James for alerting me to this.
+
+ MYRITER it = std::find_if(this->rbegin(), this->rend(), NotSpace<CT>());
+ if ( !(this->rend() == it) )
+ this->erase(this->rend() - it);
+
+ this->erase(!(it == this->rend()) ? this->find_last_of(*it) + 1 : 0);
+ return *this;
+ }
+
+ MYTYPE& TrimRight(CT tTrim)
+ {
+ MYSIZE nIdx = this->find_last_not_of(tTrim);
+ this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
+ return *this;
+ }
+
+ MYTYPE& TrimRight(PCMYSTR szTrimChars)
+ {
+ MYSIZE nIdx = this->find_last_not_of(szTrimChars);
+ this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
+ return *this;
+ }
+
+ void FreeExtra()
+ {
+ MYTYPE mt;
+ this->swap(mt);
+ if ( !mt.empty() )
+ this->assign(mt.c_str(), mt.size());
+ }
+
+ // I have intentionally not implemented the following CString
+ // functions. You cannot make them work without taking advantage
+ // of implementation specific behavior. However if you absolutely
+ // MUST have them, uncomment out these lines for "sort-of-like"
+ // their behavior. You're on your own.
+
+// CT* LockBuffer() { return GetBuf(); }// won't really lock
+// void UnlockBuffer(); { } // why have UnlockBuffer w/o LockBuffer?
+
+ // Array-indexing operators. Required because we defined an implicit cast
+ // to operator const CT* (Thanks to Julian Selman for pointing this out)
+
+ CT& operator[](int nIdx)
+ {
+ return static_cast<MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
+ }
+
+ const CT& operator[](int nIdx) const
+ {
+ return static_cast<const MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
+ }
+
+ CT& operator[](unsigned int nIdx)
+ {
+ return static_cast<MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
+ }
+
+ const CT& operator[](unsigned int nIdx) const
+ {
+ return static_cast<const MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
+ }
+
+ CT& operator[](unsigned long nIdx)
+ {
+ return static_cast<MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
+ }
+
+ const CT& operator[](unsigned long nIdx) const
+ {
+ return static_cast<const MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
+ }
+
+#ifndef SS_NO_IMPLICIT_CAST
+ operator const CT*() const
+ {
+ return this->c_str();
+ }
+#endif
+
+ // IStream related functions. Useful in IPersistStream implementations
+
+#ifdef SS_INC_COMDEF
+
+ // struct SSSHDR - useful for non Std C++ persistence schemes.
+ typedef struct SSSHDR
+ {
+ BYTE byCtrl;
+ ULONG nChars;
+ } SSSHDR; // as in "Standard String Stream Header"
+
+ #define SSSO_UNICODE 0x01 // the string is a wide string
+ #define SSSO_COMPRESS 0x02 // the string is compressed
+
+ // -------------------------------------------------------------------------
+ // FUNCTION: StreamSize
+ // REMARKS:
+ // Returns how many bytes it will take to StreamSave() this CStdString
+ // object to an IStream.
+ // -------------------------------------------------------------------------
+ ULONG StreamSize() const
+ {
+ // Control header plus string
+ ASSERT(this->size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
+ return (this->size() * sizeof(CT)) + sizeof(SSSHDR);
+ }
+
+ // -------------------------------------------------------------------------
+ // FUNCTION: StreamSave
+ // REMARKS:
+ // Saves this CStdString object to a COM IStream.
+ // -------------------------------------------------------------------------
+ HRESULT StreamSave(IStream* pStream) const
+ {
+ ASSERT(this->size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
+ HRESULT hr = E_FAIL;
+ ASSERT(pStream != 0);
+ SSSHDR hdr;
+ hdr.byCtrl = sizeof(CT) == 2 ? SSSO_UNICODE : 0;
+ hdr.nChars = this->size();
+
+
+ if ( FAILED(hr=pStream->Write(&hdr, sizeof(SSSHDR), 0)) )
+ {
+ TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),hr);
+ }
+ else if ( empty() )
+ {
+ ; // nothing to write
+ }
+ else if ( FAILED(hr=pStream->Write(this->c_str(),
+ this->size()*sizeof(CT), 0)) )
+ {
+ TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr);
+ }
+
+ return hr;
+ }
+
+
+ // -------------------------------------------------------------------------
+ // FUNCTION: StreamLoad
+ // REMARKS:
+ // This method loads the object from an IStream.
+ // -------------------------------------------------------------------------
+ HRESULT StreamLoad(IStream* pStream)
+ {
+ ASSERT(pStream != 0);
+ SSSHDR hdr;
+ HRESULT hr = E_FAIL;
+
+ if ( FAILED(hr=pStream->Read(&hdr, sizeof(SSSHDR), 0)) )
+ {
+ TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr);
+ }
+ else if ( hdr.nChars > 0 )
+ {
+ ULONG nRead = 0;
+ PMYSTR pMyBuf = BufferSet(hdr.nChars);
+
+ // If our character size matches the character size of the string
+ // we're trying to read, then we can read it directly into our
+ // buffer. Otherwise, we have to read into an intermediate buffer
+ // and convert.
+
+ if ( (hdr.byCtrl & SSSO_UNICODE) != 0 )
+ {
+ ULONG nBytes = hdr.nChars * sizeof(wchar_t);
+ if ( sizeof(CT) == sizeof(wchar_t) )
+ {
+ if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
+ TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
+ }
+ else
+ {
+ PWSTR pBufW = reinterpret_cast<PWSTR>(_alloca((nBytes)+1));
+ if ( FAILED(hr=pStream->Read(pBufW, nBytes, &nRead)) )
+ TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
+ else
+ sscpy(pMyBuf, pBufW, hdr.nChars);
+ }
+ }
+ else
+ {
+ ULONG nBytes = hdr.nChars * sizeof(char);
+ if ( sizeof(CT) == sizeof(char) )
+ {
+ if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
+ TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
+ }
+ else
+ {
+ PSTR pBufA = reinterpret_cast<PSTR>(_alloca(nBytes));
+ if ( FAILED(hr=pStream->Read(pBufA, hdr.nChars, &nRead)) )
+ TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
+ else
+ sscpy(pMyBuf, pBufA, hdr.nChars);
+ }
+ }
+ }
+ else
+ {
+ this->erase();
+ }
+ return hr;
+ }
+#endif // #ifdef SS_INC_COMDEF
+
+#ifndef SS_ANSI
+
+ // SetResourceHandle/GetResourceHandle. In MFC builds, these map directly
+ // to AfxSetResourceHandle and AfxGetResourceHandle. In non-MFC builds they
+ // point to a single static HINST so that those who call the member
+ // functions that take resource IDs can provide an alternate HINST of a DLL
+ // to search. This is not exactly the list of HMODULES that MFC provides
+ // but it's better than nothing.
+
+ #ifdef _MFC_VER
+ static void SetResourceHandle(HMODULE hNew)
+ {
+ AfxSetResourceHandle(hNew);
+ }
+ static HMODULE GetResourceHandle()
+ {
+ return AfxGetResourceHandle();
+ }
+ #else
+ static void SetResourceHandle(HMODULE hNew)
+ {
+ SSResourceHandle() = hNew;
+ }
+ static HMODULE GetResourceHandle()
+ {
+ return SSResourceHandle();
+ }
+ #endif
+
+#endif
+};
+
+// -----------------------------------------------------------------------------
+// MSVC USERS: HOW TO EXPORT CSTDSTRING FROM A DLL
+//
+// If you are using MS Visual C++ and you want to export CStdStringA and
+// CStdStringW from a DLL, then all you need to
+//
+// 1. make sure that all components link to the same DLL version
+// of the CRT (not the static one).
+// 2. Uncomment the 3 lines of code below
+// 3. #define 2 macros per the instructions in MS KnowledgeBase
+// article Q168958. The macros are:
+//
+// MACRO DEFINTION WHEN EXPORTING DEFINITION WHEN IMPORTING
+// ----- ------------------------ -------------------------
+// SSDLLEXP (nothing, just #define it) extern
+// SSDLLSPEC __declspec(dllexport) __declspec(dllimport)
+//
+// Note that these macros must be available to ALL clients who want to
+// link to the DLL and use the class. If they
+//
+// A word of advice: Don't bother.
+//
+// Really, it is not necessary to export CStdString functions from a DLL. I
+// never do. In my projects, I do generally link to the DLL version of the
+// Standard C++ Library, but I do NOT attempt to export CStdString functions.
+// I simply include the header where it is needed and allow for the code
+// redundancy.
+//
+// That redundancy is a lot less than you think. This class does most of its
+// work via the Standard C++ Library, particularly the base_class basic_string<>
+// member functions. Most of the functions here are small enough to be inlined
+// anyway. Besides, you'll find that in actual practice you use less than 1/2
+// of the code here, even in big projects and different modules will use as
+// little as 10% of it. That means a lot less functions actually get linked
+// your binaries. If you export this code from a DLL, it ALL gets linked in.
+//
+// I've compared the size of the binaries from exporting vs NOT exporting. Take
+// my word for it -- exporting this code is not worth the hassle.
+//
+// -----------------------------------------------------------------------------
+//#pragma warning(disable:4231) // non-standard extension ("extern template")
+// SSDLLEXP template class SSDLLSPEC CStdStr<char>;
+// SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;
+
+
+// =============================================================================
+// END OF CStdStr INLINE FUNCTION DEFINITIONS
+// =============================================================================
+
+// Now typedef our class names based upon this humongous template
+
+typedef CStdStr<char> CStdStringA; // a better std::string
+typedef CStdStr<wchar_t> CStdStringW; // a better std::wstring
+typedef CStdStr<uint16_t> CStdString16; // a 16bit char string
+typedef CStdStr<uint32_t> CStdString32; // a 32bit char string
+typedef CStdStr<OLECHAR> CStdStringO; // almost always CStdStringW
+
+// -----------------------------------------------------------------------------
+// CStdStr addition functions defined as inline
+// -----------------------------------------------------------------------------
+
+
+inline CStdStringA operator+(const CStdStringA& s1, const CStdStringA& s2)
+{
+ CStdStringA sRet(SSREF(s1));
+ sRet.append(s2);
+ return sRet;
+}
+inline CStdStringA operator+(const CStdStringA& s1, CStdStringA::value_type t)
+{
+ CStdStringA sRet(SSREF(s1));
+ sRet.append(1, t);
+ return sRet;
+}
+inline CStdStringA operator+(const CStdStringA& s1, PCSTR pA)
+{
+ CStdStringA sRet(SSREF(s1));
+ sRet.append(pA);
+ return sRet;
+}
+inline CStdStringA operator+(PCSTR pA, const CStdStringA& sA)
+{
+ CStdStringA sRet;
+ CStdStringA::size_type nObjSize = sA.size();
+ CStdStringA::size_type nLitSize =
+ static_cast<CStdStringA::size_type>(sslen(pA));
+
+ sRet.reserve(nLitSize + nObjSize);
+ sRet.assign(pA);
+ sRet.append(sA);
+ return sRet;
+}
+
+
+inline CStdStringA operator+(const CStdStringA& s1, const CStdStringW& s2)
+{
+ return s1 + CStdStringA(s2);
+}
+inline CStdStringW operator+(const CStdStringW& s1, const CStdStringW& s2)
+{
+ CStdStringW sRet(SSREF(s1));
+ sRet.append(s2);
+ return sRet;
+}
+inline CStdStringA operator+(const CStdStringA& s1, PCWSTR pW)
+{
+ return s1 + CStdStringA(pW);
+}
+
+#ifdef UNICODE
+ inline CStdStringW operator+(PCWSTR pW, const CStdStringA& sA)
+ {
+ return CStdStringW(pW) + CStdStringW(SSREF(sA));
+ }
+ inline CStdStringW operator+(PCSTR pA, const CStdStringW& sW)
+ {
+ return CStdStringW(pA) + sW;
+ }
+#else
+ inline CStdStringA operator+(PCWSTR pW, const CStdStringA& sA)
+ {
+ return CStdStringA(pW) + sA;
+ }
+ inline CStdStringA operator+(PCSTR pA, const CStdStringW& sW)
+ {
+ return pA + CStdStringA(sW);
+ }
+#endif
+
+// ...Now the wide string versions.
+inline CStdStringW operator+(const CStdStringW& s1, CStdStringW::value_type t)
+{
+ CStdStringW sRet(SSREF(s1));
+ sRet.append(1, t);
+ return sRet;
+}
+inline CStdStringW operator+(const CStdStringW& s1, PCWSTR pW)
+{
+ CStdStringW sRet(SSREF(s1));
+ sRet.append(pW);
+ return sRet;
+}
+inline CStdStringW operator+(PCWSTR pW, const CStdStringW& sW)
+{
+ CStdStringW sRet;
+ CStdStringW::size_type nObjSize = sW.size();
+ CStdStringA::size_type nLitSize =
+ static_cast<CStdStringW::size_type>(sslen(pW));
+
+ sRet.reserve(nLitSize + nObjSize);
+ sRet.assign(pW);
+ sRet.append(sW);
+ return sRet;
+}
+
+inline CStdStringW operator+(const CStdStringW& s1, const CStdStringA& s2)
+{
+ return s1 + CStdStringW(s2);
+}
+inline CStdStringW operator+(const CStdStringW& s1, PCSTR pA)
+{
+ return s1 + CStdStringW(pA);
+}
+
+
+// New-style format function is a template
+
+#ifdef SS_SAFE_FORMAT
+
+template<>
+struct FmtArg<CStdStringA>
+{
+ explicit FmtArg(const CStdStringA& arg) : a_(arg) {}
+ PCSTR operator()() const { return a_.c_str(); }
+ const CStdStringA& a_;
+private:
+ FmtArg<CStdStringA>& operator=(const FmtArg<CStdStringA>&) { return *this; }
+};
+template<>
+struct FmtArg<CStdStringW>
+{
+ explicit FmtArg(const CStdStringW& arg) : a_(arg) {}
+ PCWSTR operator()() const { return a_.c_str(); }
+ const CStdStringW& a_;
+private:
+ FmtArg<CStdStringW>& operator=(const FmtArg<CStdStringW>&) { return *this; }
+};
+
+template<>
+struct FmtArg<std::string>
+{
+ explicit FmtArg(const std::string& arg) : a_(arg) {}
+ PCSTR operator()() const { return a_.c_str(); }
+ const std::string& a_;
+private:
+ FmtArg<std::string>& operator=(const FmtArg<std::string>&) { return *this; }
+};
+template<>
+struct FmtArg<std::wstring>
+{
+ explicit FmtArg(const std::wstring& arg) : a_(arg) {}
+ PCWSTR operator()() const { return a_.c_str(); }
+ const std::wstring& a_;
+private:
+ FmtArg<std::wstring>& operator=(const FmtArg<std::wstring>&) {return *this;}
+};
+#endif // #ifdef SS_SAFEFORMAT
+
+#ifndef SS_ANSI
+ // SSResourceHandle: our MFC-like resource handle
+ inline HMODULE& SSResourceHandle()
+ {
+ static HMODULE hModuleSS = GetModuleHandle(0);
+ return hModuleSS;
+ }
+#endif
+
+
+// In MFC builds, define some global serialization operators
+// Special operators that allow us to serialize CStdStrings to CArchives.
+// Note that we use an intermediate CString object in order to ensure that
+// we use the exact same format.
+
+#ifdef _MFC_VER
+ inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringA& strA)
+ {
+ CString strTemp = strA;
+ return ar << strTemp;
+ }
+ inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringW& strW)
+ {
+ CString strTemp = strW;
+ return ar << strTemp;
+ }
+
+ inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringA& strA)
+ {
+ CString strTemp;
+ ar >> strTemp;
+ strA = strTemp;
+ return ar;
+ }
+ inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringW& strW)
+ {
+ CString strTemp;
+ ar >> strTemp;
+ strW = strTemp;
+ return ar;
+ }
+#endif // #ifdef _MFC_VER -- (i.e. is this MFC?)
+
+
+
+// -----------------------------------------------------------------------------
+// GLOBAL FUNCTION: WUFormat
+// CStdStringA WUFormat(UINT nId, ...);
+// CStdStringA WUFormat(PCSTR szFormat, ...);
+//
+// REMARKS:
+// This function allows the caller for format and return a CStdStringA
+// object with a single line of code.
+// -----------------------------------------------------------------------------
+#ifdef SS_ANSI
+#else
+ inline CStdStringA WUFormatA(UINT nId, ...)
+ {
+ va_list argList;
+ va_start(argList, nId);
+
+ CStdStringA strFmt;
+ CStdStringA strOut;
+ if ( strFmt.Load(nId) )
+ strOut.FormatV(strFmt, argList);
+
+ va_end(argList);
+ return strOut;
+ }
+ inline CStdStringA WUFormatA(PCSTR szFormat, ...)
+ {
+ va_list argList;
+ va_start(argList, szFormat);
+ CStdStringA strOut;
+ strOut.FormatV(szFormat, argList);
+ va_end(argList);
+ return strOut;
+ }
+ inline CStdStringW WUFormatW(UINT nId, ...)
+ {
+ va_list argList;
+ va_start(argList, nId);
+
+ CStdStringW strFmt;
+ CStdStringW strOut;
+ if ( strFmt.Load(nId) )
+ strOut.FormatV(strFmt, argList);
+
+ va_end(argList);
+ return strOut;
+ }
+ inline CStdStringW WUFormatW(PCWSTR szwFormat, ...)
+ {
+ va_list argList;
+ va_start(argList, szwFormat);
+ CStdStringW strOut;
+ strOut.FormatV(szwFormat, argList);
+ va_end(argList);
+ return strOut;
+ }
+#endif // #ifdef SS_ANSI
+
+
+
+#if defined(SS_WIN32) && !defined (SS_ANSI)
+ // -------------------------------------------------------------------------
+ // FUNCTION: WUSysMessage
+ // CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
+ // CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
+ //
+ // DESCRIPTION:
+ // This function simplifies the process of obtaining a string equivalent
+ // of a system error code returned from GetLastError(). You simply
+ // supply the value returned by GetLastError() to this function and the
+ // corresponding system string is returned in the form of a CStdStringA.
+ //
+ // PARAMETERS:
+ // dwError - a DWORD value representing the error code to be translated
+ // dwLangId - the language id to use. defaults to english.
+ //
+ // RETURN VALUE:
+ // a CStdStringA equivalent of the error code. Currently, this function
+ // only returns either English of the system default language strings.
+ // -------------------------------------------------------------------------
+ #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
+ inline CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
+ {
+ CHAR szBuf[512];
+
+ if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
+ dwLangId, szBuf, 511, NULL) )
+ return WUFormatA("%s (0x%X)", szBuf, dwError);
+ else
+ return WUFormatA("Unknown error (0x%X)", dwError);
+ }
+ inline CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
+ {
+ WCHAR szBuf[512];
+
+ if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
+ dwLangId, szBuf, 511, NULL) )
+ return WUFormatW(L"%s (0x%X)", szBuf, dwError);
+ else
+ return WUFormatW(L"Unknown error (0x%X)", dwError);
+ }
+#endif
+
+// Define TCHAR based friendly names for some of these functions
+
+#ifdef UNICODE
+ //#define CStdString CStdStringW
+ typedef CStdStringW CStdString;
+ #define WUSysMessage WUSysMessageW
+ #define WUFormat WUFormatW
+#else
+ //#define CStdString CStdStringA
+ typedef CStdStringA CStdString;
+ #define WUSysMessage WUSysMessageA
+ #define WUFormat WUFormatA
+#endif
+
+// ...and some shorter names for the space-efficient
+
+#define WUSysMsg WUSysMessage
+#define WUSysMsgA WUSysMessageA
+#define WUSysMsgW WUSysMessageW
+#define WUFmtA WUFormatA
+#define WUFmtW WUFormatW
+#define WUFmt WUFormat
+#define WULastErrMsg() WUSysMessage(::GetLastError())
+#define WULastErrMsgA() WUSysMessageA(::GetLastError())
+#define WULastErrMsgW() WUSysMessageW(::GetLastError())
+
+
+// -----------------------------------------------------------------------------
+// FUNCTIONAL COMPARATORS:
+// REMARKS:
+// These structs are derived from the std::binary_function template. They
+// give us functional classes (which may be used in Standard C++ Library
+// collections and algorithms) that perform case-insensitive comparisons of
+// CStdString objects. This is useful for maps in which the key may be the
+// proper string but in the wrong case.
+// -----------------------------------------------------------------------------
+#define StdStringLessNoCaseW SSLNCW // avoid VC compiler warning 4786
+#define StdStringEqualsNoCaseW SSENCW
+#define StdStringLessNoCaseA SSLNCA
+#define StdStringEqualsNoCaseA SSENCA
+
+#ifdef UNICODE
+ #define StdStringLessNoCase SSLNCW
+ #define StdStringEqualsNoCase SSENCW
+#else
+ #define StdStringLessNoCase SSLNCA
+ #define StdStringEqualsNoCase SSENCA
+#endif
+
+struct StdStringLessNoCaseW
+ : std::binary_function<CStdStringW, CStdStringW, bool>
+{
+ inline
+ bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
+ { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
+};
+struct StdStringEqualsNoCaseW
+ : std::binary_function<CStdStringW, CStdStringW, bool>
+{
+ inline
+ bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
+ { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
+};
+struct StdStringLessNoCaseA
+ : std::binary_function<CStdStringA, CStdStringA, bool>
+{
+ inline
+ bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
+ { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
+};
+struct StdStringEqualsNoCaseA
+ : std::binary_function<CStdStringA, CStdStringA, bool>
+{
+ inline
+ bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
+ { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
+};
+
+// If we had to define our own version of TRACE above, get rid of it now
+
+#ifdef TRACE_DEFINED_HERE
+ #undef TRACE
+ #undef TRACE_DEFINED_HERE
+#endif
+
+
+// These std::swap specializations come courtesy of Mike Crusader.
+
+//namespace std
+//{
+// inline void swap(CStdStringA& s1, CStdStringA& s2) throw()
+// {
+// s1.swap(s2);
+// }
+// template<>
+// inline void swap(CStdStringW& s1, CStdStringW& s2) throw()
+// {
+// s1.swap(s2);
+// }
+//}
+
+// Turn back on any Borland warnings we turned off.
+
+#ifdef __BORLANDC__
+ #pragma option pop // Turn back on inline function warnings
+// #pragma warn +inl // Turn back on inline function warnings
+#endif
+
+typedef std::vector<CStdString> CStdStringArray;
+
+#endif // #ifndef STDSTRING_H
diff --git a/guilib/Texture.cpp b/guilib/Texture.cpp
new file mode 100644
index 0000000000..89c16632c3
--- /dev/null
+++ b/guilib/Texture.cpp
@@ -0,0 +1,177 @@
+/*
+* Copyright (C) 2005-2008 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+#include "Texture.h"
+#include "Picture.h"
+#include "WindowingFactory.h"
+#include "utils/log.h"
+
+#define MAX_PICTURE_WIDTH 2048
+#define MAX_PICTURE_HEIGHT 2048
+
+/************************************************************************/
+/* */
+/************************************************************************/
+CBaseTexture::CBaseTexture(unsigned int width, unsigned int height, unsigned int BPP)
+{
+ m_imageWidth = width;
+ m_imageHeight = height;
+ m_pTexture = NULL;
+ m_pPixels = NULL;
+ m_nBPP = BPP;
+ m_loadedToGPU = false;
+ m_nTextureHeight = 0;
+ m_nTextureWidth = 0;
+}
+
+CBaseTexture::~CBaseTexture()
+{
+ delete[] m_pPixels;
+}
+
+void CBaseTexture::Allocate(unsigned int width, unsigned int height, unsigned int BPP)
+{
+ if (BPP != 0)
+ m_nBPP = BPP;
+
+ m_imageWidth = width;
+ m_imageHeight = height;
+
+ if (g_Windowing.NeedPower2Texture())
+ {
+ m_nTextureWidth = PadPow2(m_imageWidth);
+ m_nTextureHeight = PadPow2(m_imageHeight);
+ }
+ else
+ {
+ m_nTextureWidth = m_imageWidth;
+ m_nTextureHeight = m_imageHeight;
+ }
+
+ delete[] m_pPixels;
+ m_pPixels = new unsigned char[m_nTextureWidth * m_nTextureHeight * m_nBPP / 8];
+}
+
+void CBaseTexture::Update(int w, int h, int pitch, const unsigned char *pixels, bool loadToGPU)
+{
+ if (pixels == NULL)
+ return;
+
+ Allocate(w, h, 0);
+
+ // Resize texture to POT if needed
+ const unsigned char *src = pixels;
+ unsigned char* resized = m_pPixels;
+
+ for (int y = 0; y < h; y++)
+ {
+ memcpy(resized, src, pitch); // make sure pitch is not bigger than our width
+ src += pitch;
+
+ // repeat last column to simulate clamp_to_edge
+ for(unsigned int i = pitch; i < m_nTextureWidth*4; i+=4)
+ memcpy(resized+i, src-4, 4);
+
+ resized += (m_nTextureWidth * 4);
+ }
+
+ // clamp to edge - repeat last row
+ unsigned char *dest = m_pPixels + h*GetPitch();
+ for (unsigned int y = h; y < m_nTextureHeight; y++)
+ {
+ memcpy(dest, dest-GetPitch(), GetPitch());
+ dest += GetPitch();
+ }
+
+ if (loadToGPU)
+ LoadToGPU();
+}
+
+bool CBaseTexture::LoadFromFile(const CStdString& texturePath)
+{
+ CPicture pic;
+ if(!pic.Load(texturePath, this, MAX_PICTURE_WIDTH, MAX_PICTURE_HEIGHT))
+ {
+ CLog::Log(LOGERROR, "Texture manager unable to load file: %s", texturePath.c_str());
+ return false;
+ }
+ return true;
+}
+
+bool CBaseTexture::LoadFromMemory(unsigned int width, unsigned int height, unsigned int pitch, unsigned int BPP, unsigned char* pPixels)
+{
+ m_imageWidth = width;
+ m_imageHeight = height;
+ m_nBPP = BPP;
+ Update(width, height, pitch, pPixels, false);
+
+ return true;
+}
+
+bool CBaseTexture::LoadPaletted(unsigned int width, unsigned int height, unsigned int pitch, const unsigned char *pixels, const COLOR *palette)
+{
+ if (pixels == NULL || palette == NULL)
+ return false;
+
+ Allocate(width, height, 32);
+
+ for (unsigned int y = 0; y < height; y++)
+ {
+ unsigned char *dest = m_pPixels + y * GetPitch();
+ const unsigned char *src = pixels + y * pitch;
+ for (unsigned int x = 0; x < width; x++)
+ {
+ COLOR col = palette[*src++];
+ *dest++ = col.b;
+ *dest++ = col.g;
+ *dest++ = col.r;
+ *dest++ = col.x;
+ }
+ // clamp to edge - repeat last column
+ for (unsigned int x = width; x < m_nTextureWidth; x++)
+ {
+ COLOR col = palette[*(src-1)];
+ *dest++ = col.b;
+ *dest++ = col.g;
+ *dest++ = col.r;
+ *dest++ = col.x;
+ }
+ }
+ // clamp to edge - repeat last row
+ unsigned char *dest = m_pPixels + height*GetPitch();
+ for (unsigned int y = height; y < m_nTextureHeight; y++)
+ {
+ memcpy(dest, dest-GetPitch(), GetPitch());
+ dest += GetPitch();
+ }
+ return true;
+}
+
+DWORD CBaseTexture::PadPow2(DWORD x)
+{
+ --x;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ return ++x;
+}
diff --git a/guilib/Texture.h b/guilib/Texture.h
new file mode 100644
index 0000000000..16a481cbe8
--- /dev/null
+++ b/guilib/Texture.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+/*!
+\file Texture.h
+\brief
+*/
+
+#ifndef GUILIB_TEXTURE_H
+#define GUILIB_TEXTURE_H
+
+#include "gui3d.h"
+#include "StdString.h"
+
+#pragma pack(1)
+struct COLOR {unsigned char b,g,r,x;}; // Windows GDI expects 4bytes per color
+#pragma pack()
+
+class CTexture;
+class CGLTexture;
+class CDXTexture;
+
+#pragma once
+
+/*!
+\ingroup textures
+\brief Base texture class, subclasses of which depend on the render spec (DX, GL etc.)
+*/
+class CBaseTexture
+{
+
+public:
+ CBaseTexture(unsigned int width = 0, unsigned int height = 0, unsigned int BPP = 0);
+ virtual ~CBaseTexture();
+
+ // TODO: Clean up this interface once things have settled down (none of these need to be virtual)
+ virtual bool LoadFromFile(const CStdString& texturePath);
+ virtual bool LoadFromMemory(unsigned int width, unsigned int height, unsigned int pitch, unsigned int BPP, unsigned char* pPixels);
+ bool LoadPaletted(unsigned int width, unsigned int height, unsigned int pitch, const unsigned char *pixels, const COLOR *palette);
+
+ virtual void CreateTextureObject() = 0;
+ virtual void DestroyTextureObject() = 0;
+ virtual void LoadToGPU() = 0;
+
+ XBMC::TexturePtr GetTextureObject() const { return m_pTexture; }
+ virtual unsigned char* GetPixels() const { return m_pPixels; }
+ virtual unsigned int GetPitch() const { return m_nTextureWidth * (m_nBPP / 8); }
+ virtual unsigned int GetTextureWidth() const { return m_nTextureWidth; };
+ virtual unsigned int GetTextureHeight() const { return m_nTextureHeight; };
+ unsigned int GetWidth() const { return m_imageWidth; }
+ unsigned int GetHeight() const { return m_imageHeight; }
+ unsigned int GetBPP() const { return m_nBPP; }
+
+ void Update(int w, int h, int pitch, const unsigned char *pixels, bool loadToGPU);
+ void Allocate(unsigned int width, unsigned int height, unsigned int BPP);
+
+ static DWORD PadPow2(DWORD x);
+
+protected:
+ unsigned int m_imageWidth;
+ unsigned int m_imageHeight;
+ unsigned int m_nTextureWidth;
+ unsigned int m_nTextureHeight;
+ unsigned int m_nBPP;
+ XBMC::TexturePtr m_pTexture;
+ unsigned char* m_pPixels;
+ bool m_loadedToGPU;
+};
+
+#if defined(HAS_GL) || defined(HAS_GLES)
+#include "TextureGL.h"
+#define CTexture CGLTexture
+#elif defined(HAS_DX)
+#include "TextureDX.h"
+#define CTexture CDXTexture
+#endif
+
+#endif
diff --git a/guilib/TextureBundle.cpp b/guilib/TextureBundle.cpp
new file mode 100644
index 0000000000..6d7176c9a6
--- /dev/null
+++ b/guilib/TextureBundle.cpp
@@ -0,0 +1,492 @@
+
+
+#include "system.h"
+#include "TextureBundle.h"
+#include "Texture.h"
+#include "GraphicContext.h"
+#include "DirectXGraphics.h"
+#include "utils/log.h"
+#ifndef _LINUX
+#include <sys/stat.h>
+#include "utils/CharsetConverter.h"
+#include "lib/liblzo/LZO1X.H"
+#else
+#include <lzo/lzo1x.h>
+#endif
+#include "SkinInfo.h"
+#include "GUISettings.h"
+#include "Util.h"
+#include "FileSystem/SpecialProtocol.h"
+#include "utils/EndianSwap.h"
+
+#if !defined(__GNUC__)
+#pragma comment(lib,"../../xbmc/lib/liblzo/lzo.lib")
+#endif
+
+// alignment of file blocks - should be a multiple of the sector size of the disk and a power of 2
+// HDD sector = 512 bytes, DVD/CD sector = 2048 bytes
+#undef ALIGN
+#define ALIGN (512)
+
+
+enum XPR_FLAGS
+{
+ XPRFLAG_PALETTE = 0x00000001,
+ XPRFLAG_ANIM = 0x00000002
+};
+
+class CAutoBuffer
+{
+ BYTE* p;
+public:
+ CAutoBuffer() { p = 0; }
+ explicit CAutoBuffer(size_t s) { p = (BYTE*)malloc(s); }
+ ~CAutoBuffer() { free(p); }
+operator BYTE*() { return p; }
+ void Set(BYTE* buf) { free(p); p = buf; }
+ bool Resize(size_t s);
+void Release() { p = 0; }
+};
+
+bool CAutoBuffer::Resize(size_t s)
+{
+ if (s == 0)
+ {
+ if (!p)
+ return false;
+ free(p);
+ p = 0;
+ return true;
+ }
+ void* q = realloc(p, s);
+ if (q)
+ {
+ p = (BYTE*)q;
+ return true;
+ }
+ return false;
+}
+
+// as above but for texture allocation (do not change from XPhysicalAlloc!)
+class CAutoTexBuffer
+{
+ BYTE* p;
+public:
+ CAutoTexBuffer() { p = 0; }
+ explicit CAutoTexBuffer(size_t s) { p = (BYTE*)XPhysicalAlloc(s, MAXULONG_PTR, 128, PAGE_READWRITE); }
+ ~CAutoTexBuffer() { if (p) XPhysicalFree(p); }
+operator BYTE*() { return p; }
+ BYTE* Set(BYTE* buf) { if (p) XPhysicalFree(p); return p = buf; }
+void Release() { p = 0; }
+};
+
+CTextureBundle::CTextureBundle(void)
+{
+ m_hFile = NULL;
+ m_themeBundle = false;
+}
+
+CTextureBundle::~CTextureBundle(void)
+{
+ if (m_hFile != NULL)
+ fclose(m_hFile);
+}
+
+bool CTextureBundle::OpenBundle()
+{
+ DWORD AlignedSize;
+ DWORD HeaderSize;
+ int Version;
+ XPR_HEADER* pXPRHeader;
+
+ if (m_hFile != NULL)
+ Cleanup();
+
+ CStdString strPath;
+
+ if (m_themeBundle)
+ {
+ // if we are the theme bundle, we only load if the user has chosen
+ // a valid theme (or the skin has a default one)
+ CStdString themeXPR = g_guiSettings.GetString("lookandfeel.skintheme");
+ if (!themeXPR.IsEmpty() && themeXPR.CompareNoCase("SKINDEFAULT"))
+ {
+ strPath = CUtil::AddFileToFolder(g_graphicsContext.GetMediaDir(), "media");
+ strPath = CUtil::AddFileToFolder(strPath, themeXPR);
+ }
+ else
+ return false;
+ }
+ else
+ strPath = CUtil::AddFileToFolder(g_graphicsContext.GetMediaDir(), "media/Textures.xpr");
+
+ strPath = PTH_IC(strPath);
+
+#ifndef _LINUX
+ CStdStringW strPathW;
+ g_charsetConverter.utf8ToW(_P(strPath), strPathW, false);
+ m_hFile = _wfopen(strPathW.c_str(), L"rb");
+#else
+ m_hFile = fopen(strPath.c_str(), "rb");
+#endif
+ if (m_hFile == NULL)
+ return false;
+
+ struct stat fileStat;
+ if (fstat(fileno(m_hFile), &fileStat) == -1)
+ return false;
+ m_TimeStamp = fileStat.st_mtime;
+
+ CAutoBuffer HeaderBuf(ALIGN);
+ DWORD n;
+
+ n = fread(HeaderBuf, 1, ALIGN, m_hFile);
+ if (n < ALIGN)
+ goto LoadError;
+
+ pXPRHeader = (XPR_HEADER*)(BYTE*)HeaderBuf;
+ pXPRHeader->dwMagic = Endian_SwapLE32(pXPRHeader->dwMagic);
+ Version = (pXPRHeader->dwMagic >> 24) - '0';
+ pXPRHeader->dwMagic -= Version << 24;
+ Version &= 0x0f;
+
+ if (pXPRHeader->dwMagic != XPR_MAGIC_VALUE || Version < 2)
+ goto LoadError;
+
+ HeaderSize = Endian_SwapLE32(pXPRHeader->dwHeaderSize);
+ AlignedSize = (HeaderSize - 1) & ~(ALIGN - 1); // align to sector, but remove the first sector
+ HeaderBuf.Resize(AlignedSize + ALIGN);
+
+ if (fseek(m_hFile, ALIGN, SEEK_SET) == -1)
+ goto LoadError;
+ n = fread(HeaderBuf + ALIGN, 1, AlignedSize, m_hFile);
+ if (n < ALIGN)
+ goto LoadError;
+
+ struct DiskFileHeader_t
+ {
+ char Name[116];
+ DWORD Offset;
+ DWORD UnpackedSize;
+ DWORD PackedSize;
+ }
+ *FileHeader;
+ FileHeader = (DiskFileHeader_t*)(HeaderBuf + sizeof(XPR_HEADER));
+
+ n = (HeaderSize - sizeof(XPR_HEADER)) / sizeof(DiskFileHeader_t);
+ for (unsigned i = 0; i < n; ++i)
+ {
+ std::pair<CStdString, FileHeader_t> entry;
+ entry.first = Normalize(FileHeader[i].Name);
+ entry.second.Offset = Endian_SwapLE32(FileHeader[i].Offset);
+ entry.second.UnpackedSize = Endian_SwapLE32(FileHeader[i].UnpackedSize);
+ entry.second.PackedSize = Endian_SwapLE32(FileHeader[i].PackedSize);
+ m_FileHeaders.insert(entry);
+ }
+
+ if (lzo_init() != LZO_E_OK)
+ goto LoadError;
+
+ return true;
+
+LoadError:
+ CLog::Log(LOGERROR, "Unable to load file: %s: %s", strPath.c_str(), strerror(errno));
+ fclose(m_hFile);
+ m_hFile = NULL;
+
+ return false;
+}
+
+void CTextureBundle::Cleanup()
+{
+ if (m_hFile != NULL)
+ fclose(m_hFile);
+ m_hFile = NULL;
+
+ m_FileHeaders.clear();
+}
+
+bool CTextureBundle::HasFile(const CStdString& Filename)
+{
+ if (m_hFile == NULL && !OpenBundle())
+ return false;
+
+ struct stat fileStat;
+ if (fstat(fileno(m_hFile), &fileStat) == -1)
+ return false;
+ if (fileStat.st_mtime > m_TimeStamp)
+ {
+ CLog::Log(LOGINFO, "Texture bundle has changed, reloading");
+ Cleanup();
+ if (!OpenBundle())
+ return false;
+ }
+
+ CStdString name = Normalize(Filename);
+ return m_FileHeaders.find(name) != m_FileHeaders.end();
+}
+
+void CTextureBundle::GetTexturesFromPath(const CStdString &path, std::vector<CStdString> &textures)
+{
+ if (path.GetLength() > 1 && path[1] == ':')
+ return;
+
+ if (m_hFile == NULL && !OpenBundle())
+ return;
+
+ CStdString testPath = Normalize(path);
+ if (!CUtil::HasSlashAtEnd(testPath))
+ testPath += "\\";
+ int testLength = testPath.GetLength();
+ std::map<CStdString, FileHeader_t>::iterator it;
+ for (it = m_FileHeaders.begin(); it != m_FileHeaders.end(); it++)
+ {
+ if (it->first.Left(testLength).Equals(testPath))
+ textures.push_back(it->first);
+ }
+}
+
+HRESULT CTextureBundle::LoadFile(const CStdString& Filename, CAutoTexBuffer& UnpackedBuf)
+{
+ if (Filename == "-")
+ return 0;
+
+ CStdString name = Normalize(Filename);
+
+ std::map<CStdString, FileHeader_t>::iterator file = m_FileHeaders.find(name);
+ if (file == m_FileHeaders.end())
+ return E_FAIL;
+
+ // found texture - allocate the necessary buffers
+ DWORD ReadSize = (file->second.PackedSize + (ALIGN - 1)) & ~(ALIGN - 1);
+ BYTE *buffer = (BYTE*)malloc(ReadSize);
+
+ if (!buffer || !UnpackedBuf.Set((BYTE*)XPhysicalAlloc(file->second.UnpackedSize, MAXULONG_PTR, 128, PAGE_READWRITE)))
+ { // failed due to lack of memory
+#ifndef _LINUX
+ MEMORYSTATUS stat;
+ GlobalMemoryStatus(&stat);
+ CLog::Log(LOGERROR, "Out of memory loading texture: %s (need %lu bytes, have %lu bytes)", name.c_str(),
+ file->second.UnpackedSize + file->second.PackedSize, stat.dwAvailPhys);
+#elif defined(__APPLE__)
+ CLog::Log(LOGERROR, "Out of memory loading texture: %s (need %lu bytes)", name.c_str(),
+ file->second.UnpackedSize + file->second.PackedSize);
+#else
+ struct sysinfo info;
+ sysinfo(&info);
+ CLog::Log(LOGERROR, "Out of memory loading texture: %s "
+ "(need %u bytes, have %lu bytes)",
+ name.c_str(), file->second.UnpackedSize + file->second.PackedSize,
+ info.totalram);
+#endif
+ free(buffer);
+ return E_OUTOFMEMORY;
+ }
+
+ // read the file into our buffer
+ DWORD n;
+ fseek(m_hFile, file->second.Offset, SEEK_SET);
+ n = fread(buffer, 1, ReadSize, m_hFile);
+ if (n < ReadSize && !feof(m_hFile))
+ {
+ CLog::Log(LOGERROR, "Error loading texture: %s: %s", Filename.c_str(), strerror(ferror(m_hFile)));
+ free(buffer);
+ return E_FAIL;
+ }
+
+ // allocate a buffer for our unpacked texture
+ lzo_uint s = file->second.UnpackedSize;
+ HRESULT hr = S_OK;
+ if (lzo1x_decompress(buffer, file->second.PackedSize, UnpackedBuf, &s, NULL) != LZO_E_OK ||
+ s != file->second.UnpackedSize)
+ {
+ CLog::Log(LOGERROR, "Error loading texture: %s: Decompression error", Filename.c_str());
+ hr = E_FAIL;
+ }
+
+ try
+ {
+ free(buffer);
+ }
+ catch (...)
+ {
+ CLog::Log(LOGERROR, "Error freeing preload buffer.");
+ }
+
+ return hr;
+}
+
+HRESULT CTextureBundle::LoadTexture(const CStdString& Filename, CBaseTexture** ppTexture,
+ int &width, int &height)
+{
+ DWORD ResDataOffset;
+ *ppTexture = NULL;
+
+ CAutoTexBuffer UnpackedBuf;
+ HRESULT r = LoadFile(Filename, UnpackedBuf);
+ if (r != S_OK)
+ return r;
+
+ D3DTexture *pTex = (D3DTexture *)(new char[sizeof (D3DTexture)]);
+ D3DPalette* pPal = 0;
+ void* ResData = 0;
+
+ WORD RealSize[2];
+
+ enum XPR_FLAGS
+ {
+ XPRFLAG_PALETTE = 0x00000001,
+ XPRFLAG_ANIM = 0x00000002
+ };
+
+ BYTE* Next = UnpackedBuf;
+
+ DWORD flags = Endian_SwapLE32(*(DWORD*)Next);
+ Next += sizeof(DWORD);
+ if ((flags & XPRFLAG_ANIM) || (flags >> 16) > 1)
+ goto PackedLoadError;
+
+ if (flags & XPRFLAG_PALETTE)
+ Next += sizeof(D3DPalette);
+
+ memcpy(pTex, Next, sizeof(D3DTexture));
+ pTex->Common = Endian_SwapLE32(pTex->Common);
+ pTex->Data = Endian_SwapLE32(pTex->Data);
+ pTex->Lock = Endian_SwapLE32(pTex->Lock);
+ pTex->Format = Endian_SwapLE32(pTex->Format);
+ pTex->Size = Endian_SwapLE32(pTex->Size);
+ Next += sizeof(D3DTexture);
+
+ memcpy(RealSize, Next, 4);
+ Next += 4;
+
+ ResDataOffset = ((Next - UnpackedBuf) + 127) & ~127;
+ ResData = UnpackedBuf + ResDataOffset;
+
+ if ((pTex->Common & D3DCOMMON_TYPE_MASK) != D3DCOMMON_TYPE_TEXTURE)
+ goto PackedLoadError;
+
+ GetTextureFromData(pTex, ResData, ppTexture);
+ delete[] pTex;
+
+ width = Endian_SwapLE16(RealSize[0]);
+ height = Endian_SwapLE16(RealSize[1]);
+/* DXMERGE - this was previously used to specify the format of the image - probably only affects directx?
+#ifndef HAS_SDL
+ D3DSURFACE_DESC desc;
+ (*ppTexture)->GetLevelDesc(0, &desc);
+ pInfo->Format = desc.Format;
+#endif
+*/
+ return S_OK;
+
+PackedLoadError:
+ CLog::Log(LOGERROR, "Error loading texture: %s: Invalid data", Filename.c_str());
+ delete[] pTex;
+ delete pPal;
+ return E_FAIL;
+}
+
+int CTextureBundle::LoadAnim(const CStdString& Filename, CBaseTexture*** ppTextures,
+ int &width, int &height, int& nLoops, int** ppDelays)
+{
+ DWORD ResDataOffset;
+ int nTextures = 0;
+
+ *ppTextures = NULL; *ppDelays = NULL;
+
+ CAutoTexBuffer UnpackedBuf;
+ HRESULT r = LoadFile(Filename, UnpackedBuf);
+ if (r != S_OK)
+ return 0;
+
+ struct AnimInfo_t
+ {
+ DWORD nLoops;
+ WORD RealSize[2];
+ }
+ *pAnimInfo;
+
+ D3DTexture** ppTex = 0;
+ void* ResData = 0;
+
+ BYTE* Next = UnpackedBuf;
+
+ DWORD flags = Endian_SwapLE32(*(DWORD*)Next);
+ Next += sizeof(DWORD);
+ if (!(flags & XPRFLAG_ANIM))
+ goto PackedAnimError;
+
+ pAnimInfo = (AnimInfo_t*)Next;
+ Next += sizeof(AnimInfo_t);
+ nLoops = Endian_SwapLE32(pAnimInfo->nLoops);
+
+ if (flags & XPRFLAG_PALETTE)
+ Next += sizeof(D3DPalette);
+
+ nTextures = flags >> 16;
+ ppTex = new D3DTexture * [nTextures];
+ *ppDelays = new int[nTextures];
+ for (int i = 0; i < nTextures; ++i)
+ {
+ ppTex[i] = (D3DTexture *)(new char[sizeof (D3DTexture)+ sizeof (DWORD)]);
+
+ memcpy(ppTex[i], Next, sizeof(D3DTexture));
+ ppTex[i]->Common = Endian_SwapLE32(ppTex[i]->Common);
+ ppTex[i]->Data = Endian_SwapLE32(ppTex[i]->Data);
+ ppTex[i]->Lock = Endian_SwapLE32(ppTex[i]->Lock);
+ ppTex[i]->Format = Endian_SwapLE32(ppTex[i]->Format);
+ ppTex[i]->Size = Endian_SwapLE32(ppTex[i]->Size);
+ Next += sizeof(D3DTexture);
+
+ (*ppDelays)[i] = Endian_SwapLE32(*(int*)Next);
+ Next += sizeof(int);
+ }
+
+ ResDataOffset = ((DWORD)(Next - UnpackedBuf) + 127) & ~127;
+ ResData = UnpackedBuf + ResDataOffset;
+
+ *ppTextures = new CBaseTexture*[nTextures];
+ for (int i = 0; i < nTextures; ++i)
+ {
+ if ((ppTex[i]->Common & D3DCOMMON_TYPE_MASK) != D3DCOMMON_TYPE_TEXTURE)
+ goto PackedAnimError;
+
+ GetTextureFromData(ppTex[i], ResData, &(*ppTextures)[i]);
+ delete[] ppTex[i];
+ }
+
+ delete[] ppTex;
+ ppTex = 0;
+
+ width = Endian_SwapLE16(pAnimInfo->RealSize[0]);
+ height = Endian_SwapLE16(pAnimInfo->RealSize[1]);
+
+ return nTextures;
+
+PackedAnimError:
+ CLog::Log(LOGERROR, "Error loading texture: %s: Invalid data", Filename.c_str());
+ if (ppTex)
+ {
+ for (int i = 0; i < nTextures; ++i)
+ delete [] ppTex[i];
+ delete [] ppTex;
+ }
+ delete [] *ppDelays;
+ return 0;
+}
+
+void CTextureBundle::SetThemeBundle(bool themeBundle)
+{
+ m_themeBundle = themeBundle;
+}
+
+// normalize to how it's stored within the bundle
+// lower case + using \\ rather than /
+CStdString CTextureBundle::Normalize(const CStdString &name)
+{
+ CStdString newName(name);
+ newName.Normalize();
+ newName.Replace('/','\\');
+ return newName;
+}
diff --git a/guilib/TextureBundle.h b/guilib/TextureBundle.h
new file mode 100644
index 0000000000..c538d760a3
--- /dev/null
+++ b/guilib/TextureBundle.h
@@ -0,0 +1,70 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "StdString.h"
+#include "system.h"
+
+#include <map>
+
+class CAutoTexBuffer;
+class CBaseTexture;
+
+class CTextureBundle
+{
+ struct FileHeader_t
+ {
+ DWORD Offset;
+ DWORD UnpackedSize;
+ DWORD PackedSize;
+ };
+
+ FILE* m_hFile;
+ time_t m_TimeStamp;
+
+ std::map<CStdString, FileHeader_t> m_FileHeaders;
+ typedef std::map<CStdString, FileHeader_t>::iterator iFiles;
+
+ bool m_themeBundle;
+
+ bool OpenBundle();
+ HRESULT LoadFile(const CStdString& Filename, CAutoTexBuffer& UnpackedBuf);
+
+public:
+ CTextureBundle(void);
+ ~CTextureBundle(void);
+
+ void Cleanup();
+
+ void SetThemeBundle(bool themeBundle);
+ bool HasFile(const CStdString& Filename);
+ void GetTexturesFromPath(const CStdString &path, std::vector<CStdString> &textures);
+ static CStdString Normalize(const CStdString &name);
+
+ HRESULT LoadTexture(const CStdString& Filename, CBaseTexture** ppTexture,
+ int &width, int &height);
+
+ int LoadAnim(const CStdString& Filename, CBaseTexture*** ppTextures,
+ int &width, int &height, int& nLoops, int** ppDelays);
+};
+
+
diff --git a/guilib/TextureDX.cpp b/guilib/TextureDX.cpp
new file mode 100644
index 0000000000..7ed3c05816
--- /dev/null
+++ b/guilib/TextureDX.cpp
@@ -0,0 +1,105 @@
+/*
+* Copyright (C) 2005-2008 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+#include "TextureDX.h"
+#include "WindowingFactory.h"
+#include "../xbmc/FileSystem/SpecialProtocol.h"
+#include "utils/log.h"
+
+#ifdef HAS_DX
+
+/************************************************************************/
+/* CDXTexture */
+/************************************************************************/
+CDXTexture::CDXTexture(unsigned int width, unsigned int height, unsigned int BPP)
+: CBaseTexture(width, height, BPP)
+{
+ Allocate(m_imageWidth, m_imageHeight, m_nBPP);
+}
+
+CDXTexture::~CDXTexture()
+{
+ DestroyTextureObject();
+}
+
+void CDXTexture::CreateTextureObject()
+{
+ D3DFORMAT format;
+
+ if (m_nBPP == 8)
+ format = D3DFMT_LIN_A8;
+ else if (m_nBPP == 32)
+ format = D3DFMT_LIN_A8R8G8B8;
+ else
+ return;
+
+ SAFE_RELEASE(m_pTexture);
+
+ D3DXCreateTexture(g_Windowing.Get3DDevice(), m_nTextureWidth, m_nTextureHeight, 1, 0, format, D3DPOOL_MANAGED , &m_pTexture);
+}
+
+void CDXTexture::DestroyTextureObject()
+{
+ SAFE_RELEASE(m_pTexture);
+}
+
+void CDXTexture::LoadToGPU()
+{
+ if (!m_pPixels)
+ {
+ // nothing to load - probably same image (no change)
+ return;
+ }
+
+ if (m_pTexture == NULL)
+ {
+ CreateTextureObject();
+ if (m_pTexture == NULL)
+ {
+ CLog::Log(LOGDEBUG, "CDXTexture::CDXTexture: Error creating new texture for size %d x %d", m_nTextureWidth, m_nTextureHeight);
+ return;
+ }
+ }
+
+ D3DLOCKED_RECT lr;
+ if ( D3D_OK == m_pTexture->LockRect( 0, &lr, NULL, 0 ))
+ {
+ DWORD destPitch = lr.Pitch;
+
+ DWORD srcPitch = m_imageWidth * m_nBPP / 8;
+ BYTE *pixels = (BYTE *)lr.pBits;
+
+ for (unsigned int y = 0; y < m_nTextureHeight; y++)
+ {
+ BYTE *dst = pixels + y * destPitch;
+ BYTE *src = m_pPixels + y * srcPitch;
+ memcpy(dst, src, srcPitch);
+ }
+ }
+ m_pTexture->UnlockRect(0);
+
+ delete [] m_pPixels;
+ m_pPixels = NULL;
+
+ m_loadedToGPU = true;
+}
+
+#endif
diff --git a/guilib/TextureDX.h b/guilib/TextureDX.h
new file mode 100644
index 0000000000..db49a9cbd7
--- /dev/null
+++ b/guilib/TextureDX.h
@@ -0,0 +1,52 @@
+/*
+* Copyright (C) 2005-2008 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+/*!
+\file TextureDX.h
+\brief
+*/
+
+#ifndef GUILIB_TEXTUREDX_H
+#define GUILIB_TEXTUREDX_H
+
+#include "Texture.h"
+
+#pragma once
+
+#ifdef HAS_DX
+
+/************************************************************************/
+/* CDXTexture */
+/************************************************************************/
+class CDXTexture : public CBaseTexture
+{
+public:
+ CDXTexture(unsigned int width = 0, unsigned int height = 0, unsigned int BPP = 0);
+ virtual ~CDXTexture();
+
+ void CreateTextureObject();
+ void DestroyTextureObject();
+ virtual void LoadToGPU();
+};
+
+#endif
+
+#endif
diff --git a/guilib/TextureGL.cpp b/guilib/TextureGL.cpp
new file mode 100644
index 0000000000..af4422a0d1
--- /dev/null
+++ b/guilib/TextureGL.cpp
@@ -0,0 +1,116 @@
+/*
+* Copyright (C) 2005-2008 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+#include "system.h"
+#include "TextureGL.h"
+#include "WindowingFactory.h"
+#include "utils/log.h"
+
+#if defined(HAS_GL) || defined(HAS_GLES)
+
+using namespace std;
+
+/************************************************************************/
+/* CGLTexture */
+/************************************************************************/
+CGLTexture::CGLTexture(unsigned int width, unsigned int height, unsigned int BPP)
+: CBaseTexture(width, height, BPP)
+{
+ m_nTextureWidth = 0;
+ m_nTextureHeight = 0;
+
+ if(m_imageWidth != 0 && m_imageHeight != 0)
+ Allocate(m_imageWidth, m_imageHeight, m_nBPP);
+}
+
+CGLTexture::~CGLTexture()
+{
+ DestroyTextureObject();
+}
+
+void CGLTexture::CreateTextureObject()
+{
+ glGenTextures(1, (GLuint*) &m_pTexture);
+}
+
+void CGLTexture::DestroyTextureObject()
+{
+ if (m_pTexture)
+ glDeleteTextures(1, (GLuint*) &m_pTexture);
+}
+
+void CGLTexture::LoadToGPU()
+{
+ if (!m_pPixels)
+ {
+ // nothing to load - probably same image (no change)
+ return;
+ }
+
+ if (m_pTexture == 0)
+ {
+ // Have OpenGL generate a texture object handle for us
+ // this happens only one time - the first time the texture is loaded
+ CreateTextureObject();
+ }
+
+ // Bind the texture object
+ glBindTexture(GL_TEXTURE_2D, m_pTexture);
+
+ // Set the texture's stretching properties
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ unsigned int maxSize = g_Windowing.GetMaxTextureSize();
+ if (m_nTextureHeight > maxSize)
+ {
+ CLog::Log(LOGERROR, "GL: Image height %d too big to fit into single texture unit, truncating to %u", m_nTextureHeight, maxSize);
+ m_nTextureHeight = maxSize;
+ }
+ if (m_nTextureWidth > maxSize)
+ {
+ CLog::Log(LOGERROR, "GL: Image width %d too big to fit into single texture unit, truncating to %u", m_nTextureWidth, maxSize);
+#ifndef HAS_GLES
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, m_nTextureWidth);
+#endif
+ m_nTextureWidth = maxSize;
+ }
+
+#ifdef HAS_GL
+ GLenum format = GL_BGRA;
+#elif HAS_GLES
+ GLenum format = GL_BGRA_EXT;
+#endif
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, m_nTextureWidth, m_nTextureHeight, 0,
+ format, GL_UNSIGNED_BYTE, m_pPixels);
+#ifndef HAS_GLES
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+#endif
+ VerifyGLState();
+
+ delete [] m_pPixels;
+ m_pPixels = NULL;
+
+ m_loadedToGPU = true;
+}
+#endif // HAS_GL
diff --git a/guilib/TextureGL.h b/guilib/TextureGL.h
new file mode 100644
index 0000000000..962c6f462d
--- /dev/null
+++ b/guilib/TextureGL.h
@@ -0,0 +1,52 @@
+/*
+* Copyright (C) 2005-2008 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+/*!
+\file TextureManager.h
+\brief
+*/
+
+#ifndef GUILIB_TEXTUREGL_H
+#define GUILIB_TEXTUREGL_H
+
+#include "Texture.h"
+
+#pragma once
+
+#if defined(HAS_GL) || defined(HAS_GLES)
+
+/************************************************************************/
+/* CGLTexture */
+/************************************************************************/
+class CGLTexture : public CBaseTexture
+{
+public:
+ CGLTexture(unsigned int width = 0, unsigned int height = 0, unsigned int BPP = 0);
+ virtual ~CGLTexture();
+
+ void CreateTextureObject();
+ virtual void DestroyTextureObject();
+ void LoadToGPU();
+};
+
+#endif
+
+#endif
diff --git a/guilib/TextureManager.cpp b/guilib/TextureManager.cpp
new file mode 100644
index 0000000000..22191b1e2c
--- /dev/null
+++ b/guilib/TextureManager.cpp
@@ -0,0 +1,579 @@
+/*
+* Copyright (C) 2005-2008 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+#include "TextureManager.h"
+#include "Texture.h"
+#include "AnimatedGif.h"
+#include "GraphicContext.h"
+#include "utils/SingleLock.h"
+#include "utils/CharsetConverter.h"
+#include "utils/log.h"
+#include "../xbmc/Util.h"
+#include "../xbmc/FileSystem/File.h"
+#include "../xbmc/FileSystem/Directory.h"
+#include <assert.h>
+
+using namespace std;
+
+CGUITextureManager g_TextureManager;
+
+/************************************************************************/
+/* */
+/************************************************************************/
+CTextureArray::CTextureArray(int width, int height, int loops, bool texCoordsArePixels)
+{
+ m_width = width;
+ m_height = height;
+ m_loops = loops;
+ m_texWidth = 0;
+ m_texHeight = 0;
+ m_texCoordsArePixels = false;
+}
+
+CTextureArray::CTextureArray()
+{
+ Reset();
+}
+
+CTextureArray::~CTextureArray()
+{
+
+}
+
+unsigned int CTextureArray::size() const
+{
+ return m_textures.size();
+}
+
+
+void CTextureArray::Reset()
+{
+ m_textures.clear();
+ m_delays.clear();
+ m_width = 0;
+ m_height = 0;
+ m_loops = 0;
+ m_texWidth = 0;
+ m_texHeight = 0;
+ m_texCoordsArePixels = false;
+}
+
+void CTextureArray::Add(CBaseTexture *texture, int delay)
+{
+ if (!texture)
+ return;
+
+ m_textures.push_back(texture);
+ m_delays.push_back(delay ? delay * 2 : 100);
+
+ m_texWidth = texture->GetTextureWidth();
+ m_texHeight = texture->GetTextureHeight();
+ m_texCoordsArePixels = false;
+}
+
+void CTextureArray::Set(CBaseTexture *texture, int width, int height)
+{
+ assert(!m_textures.size()); // don't try and set a texture if we already have one!
+ m_width = width;
+ m_height = height;
+ Add(texture, 100);
+}
+
+void CTextureArray::Free()
+{
+ CSingleLock lock(g_graphicsContext);
+ for (unsigned int i = 0; i < m_textures.size(); i++)
+ {
+ delete m_textures[i];
+ }
+
+ m_textures.clear();
+ m_delays.clear();
+
+ Reset();
+}
+
+
+/************************************************************************/
+/* */
+/************************************************************************/
+
+CTextureMap::CTextureMap()
+{
+ m_textureName = "";
+ m_referenceCount = 0;
+ m_memUsage = 0;
+}
+
+CTextureMap::CTextureMap(const CStdString& textureName, int width, int height, int loops)
+: m_texture(width, height, loops)
+{
+ m_textureName = textureName;
+ m_referenceCount = 0;
+ m_memUsage = 0;
+}
+
+CTextureMap::~CTextureMap()
+{
+ FreeTexture();
+}
+
+bool CTextureMap::Release()
+{
+ if (!m_texture.m_textures.size())
+ return true;
+ if (!m_referenceCount)
+ return true;
+
+ m_referenceCount--;
+ if (!m_referenceCount)
+ {
+ return true;
+ }
+ return false;
+}
+
+const CStdString& CTextureMap::GetName() const
+{
+ return m_textureName;
+}
+
+const CTextureArray& CTextureMap::GetTexture()
+{
+ m_referenceCount++;
+ return m_texture;
+}
+
+void CTextureMap::Dump() const
+{
+ if (!m_referenceCount)
+ return; // nothing to see here
+
+ CStdString strLog;
+ strLog.Format(" texture:%s has %i frames %i refcount\n", m_textureName.c_str(), m_texture.m_textures.size(), m_referenceCount);
+ OutputDebugString(strLog.c_str());
+}
+
+DWORD CTextureMap::GetMemoryUsage() const
+{
+ return m_memUsage;
+}
+
+void CTextureMap::Flush()
+{
+ if (!m_referenceCount)
+ FreeTexture();
+}
+
+
+void CTextureMap::FreeTexture()
+{
+ m_texture.Free();
+}
+
+bool CTextureMap::IsEmpty() const
+{
+ return m_texture.m_textures.size() == 0;
+}
+
+void CTextureMap::Add(CBaseTexture* texture, int delay)
+{
+ m_texture.Add(texture, delay);
+
+ if (texture)
+ m_memUsage += sizeof(CTexture) + (texture->GetTextureWidth() * texture->GetTextureHeight() * 4);
+}
+
+/************************************************************************/
+/* */
+/************************************************************************/
+CGUITextureManager::CGUITextureManager(void)
+{
+ // we set the theme bundle to be the first bundle (thus prioritizing it)
+ m_TexBundle[0].SetThemeBundle(true);
+}
+
+CGUITextureManager::~CGUITextureManager(void)
+{
+ Cleanup();
+}
+
+const CTextureArray& CGUITextureManager::GetTexture(const CStdString& strTextureName)
+{
+ static CTextureArray emptyTexture;
+ // CLog::Log(LOGINFO, " refcount++ for GetTexture(%s)\n", strTextureName.c_str());
+ for (int i = 0; i < (int)m_vecTextures.size(); ++i)
+ {
+ CTextureMap *pMap = m_vecTextures[i];
+ if (pMap->GetName() == strTextureName)
+ {
+ //CLog::Log(LOGDEBUG, "Total memusage %u", GetMemoryUsage());
+ return pMap->GetTexture();
+ }
+ }
+ return emptyTexture;
+}
+
+
+
+
+/************************************************************************/
+/* */
+/************************************************************************/
+bool CGUITextureManager::CanLoad(const CStdString &texturePath) const
+{
+ if (texturePath == "-")
+ return false;
+
+ if (!CURL::IsFullPath(texturePath))
+ return true; // assume we have it
+
+ // we can't (or shouldn't) be loading from remote paths, so check these
+ return CUtil::IsHD(texturePath);
+}
+
+bool CGUITextureManager::HasTexture(const CStdString &textureName, CStdString *path, int *bundle, int *size)
+{
+ // default values
+ if (bundle) *bundle = -1;
+ if (size) *size = 0;
+ if (path) *path = textureName;
+
+ if (!CanLoad(textureName))
+ return false;
+
+ // Check our loaded and bundled textures - we store in bundles using \\.
+ CStdString bundledName = CTextureBundle::Normalize(textureName);
+ for (int i = 0; i < (int)m_vecTextures.size(); ++i)
+ {
+ CTextureMap *pMap = m_vecTextures[i];
+ if (pMap->GetName() == textureName)
+ {
+ if (size) *size = 1;
+ return true;
+ }
+ }
+
+ for (int i = 0; i < 2; i++)
+ {
+ if (m_TexBundle[i].HasFile(bundledName))
+ {
+ if (bundle) *bundle = i;
+ return true;
+ }
+ }
+
+ CStdString fullPath = GetTexturePath(textureName);
+ if (path)
+ *path = fullPath;
+
+ return !fullPath.IsEmpty();
+}
+
+int CGUITextureManager::Load(const CStdString& strTextureName, bool checkBundleOnly /*= false */)
+{
+ CStdString strPath;
+ int bundle = -1;
+ int size = 0;
+ if (!HasTexture(strTextureName, &strPath, &bundle, &size))
+ return 0;
+
+ if (size) // we found the texture
+ return size;
+
+ if (checkBundleOnly && bundle == -1)
+ return 0;
+
+ //Lock here, we will do stuff that could break rendering
+ CSingleLock lock(g_graphicsContext);
+
+#ifdef _DEBUG
+ LARGE_INTEGER start;
+ QueryPerformanceCounter(&start);
+#endif
+
+ if (strPath.Right(4).ToLower() == ".gif")
+ {
+ CTextureMap* pMap;
+
+ if (bundle >= 0)
+ {
+ CBaseTexture **pTextures;
+ int nLoops = 0, width = 0, height = 0;
+ int* Delay;
+ int nImages = m_TexBundle[bundle].LoadAnim(strTextureName, &pTextures, width, height, nLoops, &Delay);
+ if (!nImages)
+ {
+ CLog::Log(LOGERROR, "Texture manager unable to load bundled file: %s", strTextureName.c_str());
+ return 0;
+ }
+
+ pMap = new CTextureMap(strTextureName, width, height, nLoops);
+ for (int iImage = 0; iImage < nImages; ++iImage)
+ {
+ pMap->Add(pTextures[iImage], Delay[iImage]);
+ }
+
+ delete [] pTextures;
+ delete [] Delay;
+ }
+ else
+ {
+ CAnimatedGifSet AnimatedGifSet;
+ int iImages = AnimatedGifSet.LoadGIF(strPath.c_str());
+ if (iImages == 0)
+ {
+ if (!strnicmp(strPath.c_str(), "special://home/skin/", 20) && !strnicmp(strPath.c_str(), "special://xbmc/skin/", 20))
+ CLog::Log(LOGERROR, "Texture manager unable to load file: %s", strPath.c_str());
+ return 0;
+ }
+ int iWidth = AnimatedGifSet.FrameWidth;
+ int iHeight = AnimatedGifSet.FrameHeight;
+
+ // fixup our palette
+ COLOR *palette = AnimatedGifSet.m_vecimg[0]->Palette;
+ // set the alpha values to fully opaque
+ for (int i = 0; i < 256; i++)
+ palette[i].x = 0xff;
+ // and set the transparent colour
+ if (AnimatedGifSet.m_vecimg[0]->Transparency && AnimatedGifSet.m_vecimg[0]->Transparent >= 0)
+ palette[AnimatedGifSet.m_vecimg[0]->Transparent].x = 0;
+
+ pMap = new CTextureMap(strTextureName, iWidth, iHeight, AnimatedGifSet.nLoops);
+
+ for (int iImage = 0; iImage < iImages; iImage++)
+ {
+ CTexture *glTexture = new CTexture();
+ if (glTexture)
+ {
+ CAnimatedGif* pImage = AnimatedGifSet.m_vecimg[iImage];
+ glTexture->LoadPaletted(pImage->Width, pImage->Height, pImage->BytesPerRow, (unsigned char *)pImage->Raster, palette);
+ pMap->Add(glTexture, pImage->Delay);
+ }
+ } // of for (int iImage=0; iImage < iImages; iImage++)
+ }
+
+#ifdef _DEBUG
+ LARGE_INTEGER end, freq;
+ QueryPerformanceCounter(&end);
+ QueryPerformanceFrequency(&freq);
+ char temp[200];
+ sprintf(temp, "Load %s: %.1fms%s\n", strPath.c_str(), 1000.f * (end.QuadPart - start.QuadPart) / freq.QuadPart, (bundle >= 0) ? " (bundled)" : "");
+ OutputDebugString(temp);
+#endif
+
+ m_vecTextures.push_back(pMap);
+ return 1;
+ } // of if (strPath.Right(4).ToLower()==".gif")
+
+ CBaseTexture *pTexture = NULL;
+ int width = 0, height = 0;
+ if (bundle >= 0)
+ {
+ if (FAILED(m_TexBundle[bundle].LoadTexture(strTextureName, &pTexture, width, height)))
+ {
+ CLog::Log(LOGERROR, "Texture manager unable to load bundled file: %s", strTextureName.c_str());
+ return 0;
+ }
+ }
+ else
+ {
+ // normal picture
+ // convert from utf8
+ CStdString texturePath;
+ g_charsetConverter.utf8ToStringCharset(strPath, texturePath);
+
+ pTexture = new CTexture();
+ pTexture->LoadFromFile(texturePath);
+ width = pTexture->GetWidth();
+ height = pTexture->GetHeight();
+ }
+
+ if (!pTexture) return 0;
+
+ CTextureMap* pMap = new CTextureMap(strTextureName, width, height, 0);
+ pMap->Add(pTexture, 100);
+ m_vecTextures.push_back(pMap);
+
+#ifdef _DEBUG_TEXTURES
+ LARGE_INTEGER end, freq;
+ QueryPerformanceCounter(&end);
+ QueryPerformanceFrequency(&freq);
+ char temp[200];
+ sprintf(temp, "Load %s: %.1fms%s\n", strPath.c_str(), 1000.f * (end.QuadPart - start.QuadPart) / freq.QuadPart, (bundle >= 0) ? " (bundled)" : "");
+ OutputDebugString(temp);
+#endif
+
+ return 1;
+}
+
+
+void CGUITextureManager::ReleaseTexture(const CStdString& strTextureName)
+{
+ CSingleLock lock(g_graphicsContext);
+
+ ivecTextures i;
+ i = m_vecTextures.begin();
+ while (i != m_vecTextures.end())
+ {
+ CTextureMap* pMap = *i;
+ if (pMap->GetName() == strTextureName)
+ {
+ if (pMap->Release())
+ {
+ //CLog::Log(LOGINFO, " cleanup:%s", strTextureName.c_str());
+ // add to our textures to free
+ m_unusedTextures.push_back(pMap);
+ i = m_vecTextures.erase(i);
+ }
+ return;
+ }
+ ++i;
+ }
+ CLog::Log(LOGWARNING, "%s: Unable to release texture %s", __FUNCTION__, strTextureName.c_str());
+}
+
+void CGUITextureManager::FreeUnusedTextures()
+{
+ CSingleLock lock(g_graphicsContext);
+ for (ivecTextures i = m_unusedTextures.begin(); i != m_unusedTextures.end(); ++i)
+ delete *i;
+ m_unusedTextures.clear();
+}
+
+void CGUITextureManager::Cleanup()
+{
+ CSingleLock lock(g_graphicsContext);
+
+ ivecTextures i;
+ i = m_vecTextures.begin();
+ while (i != m_vecTextures.end())
+ {
+ CTextureMap* pMap = *i;
+ CLog::Log(LOGWARNING, "%s: Having to cleanup texture %s", __FUNCTION__, pMap->GetName().c_str());
+ delete pMap;
+ i = m_vecTextures.erase(i);
+ }
+ for (int i = 0; i < 2; i++)
+ m_TexBundle[i].Cleanup();
+}
+
+void CGUITextureManager::Dump() const
+{
+ CStdString strLog;
+ strLog.Format("total texturemaps size:%i\n", m_vecTextures.size());
+ OutputDebugString(strLog.c_str());
+
+ for (int i = 0; i < (int)m_vecTextures.size(); ++i)
+ {
+ const CTextureMap* pMap = m_vecTextures[i];
+ if (!pMap->IsEmpty())
+ pMap->Dump();
+ }
+}
+
+void CGUITextureManager::Flush()
+{
+ CSingleLock lock(g_graphicsContext);
+
+ ivecTextures i;
+ i = m_vecTextures.begin();
+ while (i != m_vecTextures.end())
+ {
+ CTextureMap* pMap = *i;
+ pMap->Flush();
+ if (pMap->IsEmpty() )
+ {
+ delete pMap;
+ i = m_vecTextures.erase(i);
+ }
+ else
+ {
+ ++i;
+ }
+ }
+}
+
+DWORD CGUITextureManager::GetMemoryUsage() const
+{
+ DWORD memUsage = 0;
+ for (int i = 0; i < (int)m_vecTextures.size(); ++i)
+ {
+ memUsage += m_vecTextures[i]->GetMemoryUsage();
+ }
+ return memUsage;
+}
+
+void CGUITextureManager::SetTexturePath(const CStdString &texturePath)
+{
+ m_texturePaths.clear();
+ AddTexturePath(texturePath);
+}
+
+void CGUITextureManager::AddTexturePath(const CStdString &texturePath)
+{
+ if (!texturePath.IsEmpty())
+ m_texturePaths.push_back(texturePath);
+}
+
+void CGUITextureManager::RemoveTexturePath(const CStdString &texturePath)
+{
+ for (vector<CStdString>::iterator it = m_texturePaths.begin(); it != m_texturePaths.end(); ++it)
+ {
+ if (*it == texturePath)
+ {
+ m_texturePaths.erase(it);
+ return;
+ }
+ }
+}
+
+CStdString CGUITextureManager::GetTexturePath(const CStdString &textureName, bool directory /* = false */)
+{
+ if (CURL::IsFullPath(textureName))
+ return textureName;
+ else
+ { // texture doesn't include the full path, so check all fallbacks
+ for (vector<CStdString>::iterator it = m_texturePaths.begin(); it != m_texturePaths.end(); ++it)
+ {
+ CStdString path = CUtil::AddFileToFolder(it->c_str(), "media");
+ path = CUtil::AddFileToFolder(path, textureName);
+ if (directory)
+ {
+ if (DIRECTORY::CDirectory::Exists(path))
+ return path;
+ }
+ else
+ {
+ if (XFILE::CFile::Exists(path))
+ return path;
+ }
+ }
+ }
+ return "";
+}
+
+void CGUITextureManager::GetBundledTexturesFromPath(const CStdString& texturePath, std::vector<CStdString> &items)
+{
+ m_TexBundle[0].GetTexturesFromPath(texturePath, items);
+ if (items.empty())
+ m_TexBundle[1].GetTexturesFromPath(texturePath, items);
+}
diff --git a/guilib/TextureManager.h b/guilib/TextureManager.h
new file mode 100644
index 0000000000..8907714011
--- /dev/null
+++ b/guilib/TextureManager.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+/*!
+\file TextureManager.h
+\brief
+*/
+
+#ifndef GUILIB_TEXTUREMANAGER_H
+#define GUILIB_TEXTUREMANAGER_H
+
+#include <vector>
+#include "TextureBundle.h"
+
+#pragma once
+
+/************************************************************************/
+/* */
+/************************************************************************/
+class CTextureArray
+{
+public:
+ CTextureArray(int width, int height, int loops, bool texCoordsArePixels = false);
+ CTextureArray();
+
+ virtual ~CTextureArray();
+
+ void Reset();
+
+ void Add(CBaseTexture *texture, int delay);
+ void Set(CBaseTexture *texture, int width, int height);
+ void Free();
+ unsigned int size() const;
+
+ std::vector<CBaseTexture* > m_textures;
+ std::vector<int> m_delays;
+ int m_width;
+ int m_height;
+ int m_loops;
+ int m_texWidth;
+ int m_texHeight;
+ bool m_texCoordsArePixels;
+};
+
+/*!
+ \ingroup textures
+ \brief
+ */
+/************************************************************************/
+/* */
+/************************************************************************/
+class CTextureMap
+{
+public:
+ CTextureMap();
+ CTextureMap(const CStdString& textureName, int width, int height, int loops);
+ virtual ~CTextureMap();
+
+ void Add(CBaseTexture* texture, int delay);
+ bool Release();
+
+ const CStdString& GetName() const;
+ const CTextureArray& GetTexture();
+ void Dump() const;
+ DWORD GetMemoryUsage() const;
+ void Flush();
+ bool IsEmpty() const;
+protected:
+ void FreeTexture();
+
+ CStdString m_textureName;
+ CTextureArray m_texture;
+ unsigned int m_referenceCount;
+ DWORD m_memUsage;
+};
+
+/*!
+ \ingroup textures
+ \brief
+ */
+/************************************************************************/
+/* */
+/************************************************************************/
+class CGUITextureManager
+{
+public:
+ CGUITextureManager(void);
+ virtual ~CGUITextureManager(void);
+
+ bool HasTexture(const CStdString &textureName, CStdString *path = NULL, int *bundle = NULL, int *size = NULL);
+ bool CanLoad(const CStdString &texturePath) const; ///< Returns true if the texture manager can load this texture
+ int Load(const CStdString& strTextureName, bool checkBundleOnly = false);
+ const CTextureArray& GetTexture(const CStdString& strTextureName);
+ void ReleaseTexture(const CStdString& strTextureName);
+ void Cleanup();
+ void Dump() const;
+ DWORD GetMemoryUsage() const;
+ void Flush();
+ CStdString GetTexturePath(const CStdString& textureName, bool directory = false);
+ void GetBundledTexturesFromPath(const CStdString& texturePath, std::vector<CStdString> &items);
+
+ void AddTexturePath(const CStdString &texturePath); ///< Add a new path to the paths to check when loading media
+ void SetTexturePath(const CStdString &texturePath); ///< Set a single path as the path to check when loading media (clear then add)
+ void RemoveTexturePath(const CStdString &texturePath); ///< Remove a path from the paths to check when loading media
+
+ void FreeUnusedTextures(); ///< Free textures (called from app thread only)
+protected:
+ std::vector<CTextureMap*> m_vecTextures;
+ std::vector<CTextureMap*> m_unusedTextures;
+ typedef std::vector<CTextureMap*>::iterator ivecTextures;
+ // we have 2 texture bundles (one for the base textures, one for the theme)
+ CTextureBundle m_TexBundle[2];
+
+ std::vector<CStdString> m_texturePaths;
+};
+
+/*!
+ \ingroup textures
+ \brief
+ */
+extern CGUITextureManager g_TextureManager;
+#endif
diff --git a/guilib/TransformMatrix.h b/guilib/TransformMatrix.h
new file mode 100644
index 0000000000..cc9c19bae6
--- /dev/null
+++ b/guilib/TransformMatrix.h
@@ -0,0 +1,240 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include <math.h>
+#include <memory>
+#include <string.h>
+#include <stdint.h>
+
+#ifdef __GNUC__
+// under gcc, inline will only take place if optimizations are applied (-O). this will force inline even whith optimizations.
+#define XBMC_FORCE_INLINE __attribute__((always_inline))
+#else
+#define XBMC_FORCE_INLINE
+#endif
+
+typedef uint32_t color_t;
+
+class TransformMatrix
+{
+public:
+ TransformMatrix()
+ {
+ Reset();
+ };
+ void Reset()
+ {
+ m[0][0] = 1.0f; m[0][1] = m[0][2] = m[0][3] = 0.0f;
+ m[1][0] = m[1][2] = m[1][3] = 0.0f; m[1][1] = 1.0f;
+ m[2][0] = m[2][1] = m[2][3] = 0.0f; m[2][2] = 1.0f;
+ alpha = 1.0f;
+ };
+ static TransformMatrix CreateTranslation(float transX, float transY, float transZ = 0)
+ {
+ TransformMatrix translation;
+ translation.m[0][3] = transX;
+ translation.m[1][3] = transY;
+ translation.m[2][3] = transZ;
+ return translation;
+ }
+ void SetTranslation(float transX, float transY, float transZ)
+ {
+ m[0][1] = m[0][2] = 0.0f; m[0][0] = 1.0f; m[0][3] = transX;
+ m[1][0] = m[1][2] = 0.0f; m[1][1] = 1.0f; m[1][3] = transY;
+ m[2][0] = m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = transZ;
+ alpha = 1.0f;
+ }
+ static TransformMatrix CreateScaler(float scaleX, float scaleY, float scaleZ = 1.0f)
+ {
+ TransformMatrix scaler;
+ scaler.m[0][0] = scaleX;
+ scaler.m[1][1] = scaleY;
+ scaler.m[2][2] = scaleZ;
+ return scaler;
+ };
+ void SetScaler(float scaleX, float scaleY, float centerX, float centerY)
+ {
+ // Trans(centerX,centerY,centerZ)*Scale(scaleX,scaleY,scaleZ)*Trans(-centerX,-centerY,-centerZ)
+ float centerZ = 0.0f, scaleZ = 1.0f;
+ m[0][0] = scaleX; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = centerX*(1-scaleX);
+ m[1][0] = 0.0f; m[1][1] = scaleY; m[1][2] = 0.0f; m[1][3] = centerY*(1-scaleY);
+ m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = scaleZ; m[2][3] = centerZ*(1-scaleZ);
+ alpha = 1.0f;
+ };
+ void SetXRotation(float angle, float y, float z, float ar = 1.0f)
+ { // angle about the X axis, centered at y,z where our coordinate system has aspect ratio ar.
+ // Trans(0,y,z)*Scale(1,1/ar,1)*RotateX(angle)*Scale(ar,1,1)*Trans(0,-y,-z);
+ float c = cos(angle); float s = sin(angle);
+ m[0][0] = ar; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = 0.0f;
+ m[1][0] = 0.0f; m[1][1] = c/ar; m[1][2] = -s/ar; m[1][3] = (-y*c+s*z)/ar + y;
+ m[2][0] = 0.0f; m[2][1] = s; m[2][2] = c; m[2][3] = (-y*s-c*z) + z;
+ angle = 1.0f;
+ }
+ void SetYRotation(float angle, float x, float z, float ar = 1.0f)
+ { // angle about the Y axis, centered at x,z where our coordinate system has aspect ratio ar.
+ // Trans(x,0,z)*Scale(1/ar,1,1)*RotateY(angle)*Scale(ar,1,1)*Trans(-x,0,-z);
+ float c = cos(angle); float s = sin(angle);
+ m[0][0] = c; m[0][1] = 0.0f; m[0][2] = -s/ar; m[0][3] = -x*c + s*z/ar + x;
+ m[1][0] = 0.0f; m[1][1] = 1.0f; m[1][2] = 0.0f; m[1][3] = 0.0f;
+ m[2][0] = ar*s; m[2][1] = 0.0f; m[2][2] = c; m[2][3] = -ar*x*s - c*z + z;
+ angle = 1.0f;
+ }
+ static TransformMatrix CreateZRotation(float angle, float x, float y, float ar = 1.0f)
+ { // angle about the Z axis, centered at x,y where our coordinate system has aspect ratio ar.
+ // Trans(x,y,0)*Scale(1/ar,1,1)*RotateZ(angle)*Scale(ar,1,1)*Trans(-x,-y,0)
+ float c = cos(angle); float s = sin(angle);
+ TransformMatrix rot;
+ rot.m[0][0] = c; rot.m[0][1] = -s/ar; rot.m[0][3] = -x*c + s*y/ar + x;
+ rot.m[1][0] = s*ar; rot.m[1][1] = c; rot.m[1][3] = -ar*x*s - c*y + y;
+ return rot;
+ }
+ void SetZRotation(float angle, float x, float y, float ar = 1.0f)
+ { // angle about the Z axis, centered at x,y where our coordinate system has aspect ratio ar.
+ // Trans(x,y,0)*Scale(1/ar,1,1)*RotateZ(angle)*Scale(ar,1,1)*Trans(-x,-y,0)
+ float c = cos(angle); float s = sin(angle);
+ m[0][0] = c; m[0][1] = -s/ar; m[0][2] = 0.0f; m[0][3] = -x*c + s*y/ar + x;
+ m[1][0] = s*ar; m[1][1] = c; m[1][2] = 0.0f; m[1][3] = -ar*x*s - c*y + y;
+ m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = 0.0f;
+ angle = 1.0f;
+ }
+ static TransformMatrix CreateFader(float a)
+ {
+ TransformMatrix fader;
+ fader.alpha = a;
+ return fader;
+ }
+ void SetFader(float a)
+ {
+ m[0][0] = 1.0f; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = 0.0f;
+ m[1][0] = 0.0f; m[1][1] = 1.0f; m[1][2] = 0.0f; m[1][3] = 0.0f;
+ m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = 0.0f;
+ alpha = a;
+ }
+ // assignment operator
+ const TransformMatrix &operator =(const TransformMatrix &right)
+ {
+ if (this != &right)
+ {
+ memcpy(m, right.m, 12*sizeof(float));
+ alpha = right.alpha;
+ }
+ return *this;
+ }
+
+ // multiplication operators
+ const TransformMatrix &operator *=(const TransformMatrix &right)
+ {
+ float t00 = m[0][0] * right.m[0][0] + m[0][1] * right.m[1][0] + m[0][2] * right.m[2][0];
+ float t01 = m[0][0] * right.m[0][1] + m[0][1] * right.m[1][1] + m[0][2] * right.m[2][1];
+ float t02 = m[0][0] * right.m[0][2] + m[0][1] * right.m[1][2] + m[0][2] * right.m[2][2];
+ m[0][3] = m[0][0] * right.m[0][3] + m[0][1] * right.m[1][3] + m[0][2] * right.m[2][3] + m[0][3];
+ m[0][0] = t00; m[0][1] = t01; m[0][2] = t02;
+ t00 = m[1][0] * right.m[0][0] + m[1][1] * right.m[1][0] + m[1][2] * right.m[2][0];
+ t01 = m[1][0] * right.m[0][1] + m[1][1] * right.m[1][1] + m[1][2] * right.m[2][1];
+ t02 = m[1][0] * right.m[0][2] + m[1][1] * right.m[1][2] + m[1][2] * right.m[2][2];
+ m[1][3] = m[1][0] * right.m[0][3] + m[1][1] * right.m[1][3] + m[1][2] * right.m[2][3] + m[1][3];
+ m[1][0] = t00; m[1][1] = t01; m[1][2] = t02;
+ t00 = m[2][0] * right.m[0][0] + m[2][1] * right.m[1][0] + m[2][2] * right.m[2][0];
+ t01 = m[2][0] * right.m[0][1] + m[2][1] * right.m[1][1] + m[2][2] * right.m[2][1];
+ t02 = m[2][0] * right.m[0][2] + m[2][1] * right.m[1][2] + m[2][2] * right.m[2][2];
+ m[2][3] = m[2][0] * right.m[0][3] + m[2][1] * right.m[1][3] + m[2][2] * right.m[2][3] + m[2][3];
+ m[2][0] = t00; m[2][1] = t01; m[2][2] = t02;
+ alpha *= right.alpha;
+ return *this;
+ }
+
+ TransformMatrix operator *(const TransformMatrix &right) const
+ {
+ TransformMatrix result;
+ result.m[0][0] = m[0][0] * right.m[0][0] + m[0][1] * right.m[1][0] + m[0][2] * right.m[2][0];
+ result.m[0][1] = m[0][0] * right.m[0][1] + m[0][1] * right.m[1][1] + m[0][2] * right.m[2][1];
+ result.m[0][2] = m[0][0] * right.m[0][2] + m[0][1] * right.m[1][2] + m[0][2] * right.m[2][2];
+ result.m[0][3] = m[0][0] * right.m[0][3] + m[0][1] * right.m[1][3] + m[0][2] * right.m[2][3] + m[0][3];
+ result.m[1][0] = m[1][0] * right.m[0][0] + m[1][1] * right.m[1][0] + m[1][2] * right.m[2][0];
+ result.m[1][1] = m[1][0] * right.m[0][1] + m[1][1] * right.m[1][1] + m[1][2] * right.m[2][1];
+ result.m[1][2] = m[1][0] * right.m[0][2] + m[1][1] * right.m[1][2] + m[1][2] * right.m[2][2];
+ result.m[1][3] = m[1][0] * right.m[0][3] + m[1][1] * right.m[1][3] + m[1][2] * right.m[2][3] + m[1][3];
+ result.m[2][0] = m[2][0] * right.m[0][0] + m[2][1] * right.m[1][0] + m[2][2] * right.m[2][0];
+ result.m[2][1] = m[2][0] * right.m[0][1] + m[2][1] * right.m[1][1] + m[2][2] * right.m[2][1];
+ result.m[2][2] = m[2][0] * right.m[0][2] + m[2][1] * right.m[1][2] + m[2][2] * right.m[2][2];
+ result.m[2][3] = m[2][0] * right.m[0][3] + m[2][1] * right.m[1][3] + m[2][2] * right.m[2][3] + m[2][3];
+ result.alpha = alpha * right.alpha;
+ return result;
+ }
+
+ inline void TransformPosition(float &x, float &y, float &z) const XBMC_FORCE_INLINE
+ {
+ float newX = m[0][0] * x + m[0][1] * y + m[0][2] * z + m[0][3];
+ float newY = m[1][0] * x + m[1][1] * y + m[1][2] * z + m[1][3];
+ z = m[2][0] * x + m[2][1] * y + m[2][2] * z + m[2][3];
+ y = newY;
+ x = newX;
+ }
+
+ inline void TransformPositionUnscaled(float &x, float &y, float &z) const XBMC_FORCE_INLINE
+ {
+ float n;
+ // calculate the norm of the transformed (but not translated) vectors involved
+ n = sqrt(m[0][0]*m[0][0] + m[0][1]*m[0][1] + m[0][2]*m[0][2]);
+ float newX = (m[0][0] * x + m[0][1] * y + m[0][2] * z)/n + m[0][3];
+ n = sqrt(m[1][0]*m[1][0] + m[1][1]*m[1][1] + m[1][2]*m[1][2]);
+ float newY = (m[1][0] * x + m[1][1] * y + m[1][2] * z)/n + m[1][3];
+ n = sqrt(m[2][0]*m[2][0] + m[2][1]*m[2][1] + m[2][2]*m[2][2]);
+ float newZ = (m[2][0] * x + m[2][1] * y + m[2][2] * z)/n + m[2][3];
+ z = newZ;
+ y = newY;
+ x = newX;
+ }
+
+ inline void InverseTransformPosition(float &x, float &y) const XBMC_FORCE_INLINE
+ { // used for mouse - no way to find z
+ x -= m[0][3]; y -= m[1][3];
+ float detM = m[0][0]*m[1][1] - m[0][1]*m[1][0];
+ float newX = (m[1][1] * x - m[0][1] * y)/detM;
+ y = (-m[1][0] * x + m[0][0] * y)/detM;
+ x = newX;
+ }
+
+ inline float TransformXCoord(float x, float y, float z) const XBMC_FORCE_INLINE
+ {
+ return m[0][0] * x + m[0][1] * y + m[0][2] * z + m[0][3];
+ }
+
+ inline float TransformYCoord(float x, float y, float z) const XBMC_FORCE_INLINE
+ {
+ return m[1][0] * x + m[1][1] * y + m[1][2] * z + m[1][3];
+ }
+
+ inline float TransformZCoord(float x, float y, float z) const XBMC_FORCE_INLINE
+ {
+ return m[2][0] * x + m[2][1] * y + m[2][2] * z + m[2][3];
+ }
+
+ inline color_t TransformAlpha(color_t colour) const XBMC_FORCE_INLINE
+ {
+ return (color_t)(colour * alpha);
+ }
+
+ float m[3][4];
+ float alpha;
+};
diff --git a/guilib/Tween.h b/guilib/Tween.h
new file mode 100644
index 0000000000..9df3bdcbb7
--- /dev/null
+++ b/guilib/Tween.h
@@ -0,0 +1,408 @@
+#ifndef __TWEEN_H__
+#define __TWEEN_H__
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+///////////////////////////////////////////////////////////////////////
+// Tween.h
+// A couple of tweening classes implemented in C++.
+// ref: http://www.robertpenner.com/easing/
+//
+// Author: d4rk <d4rk@xbmc.org>
+///////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////
+// Current list of classes:
+//
+// LinearTweener
+// QuadTweener
+// CubicTweener
+// SineTweener
+// CircleTweener
+// BackTweener
+// BounceTweener
+// ElasticTweener
+//
+///////////////////////////////////////////////////////////////////////
+
+#include <math.h>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846f
+#endif
+
+enum TweenerType
+{
+ EASE_IN,
+ EASE_OUT,
+ EASE_INOUT
+};
+
+
+class Tweener
+{
+public:
+ Tweener(TweenerType tweenerType = EASE_OUT) { m_tweenerType = tweenerType; _ref=1; }
+ virtual ~Tweener() {};
+
+ void SetEasing(TweenerType type) { m_tweenerType = type; }
+ virtual float Tween(float time, float start, float change, float duration)=0;
+ void Free() { _ref--; if (_ref==0) delete this; }
+ void IncRef() { _ref++; }
+
+protected:
+ int _ref;
+ TweenerType m_tweenerType;
+};
+
+
+class LinearTweener : public Tweener
+{
+public:
+ virtual float Tween(float time, float start, float change, float duration)
+ {
+ return change * time / duration + start;
+ }
+};
+
+
+class QuadTweener : public Tweener
+{
+public:
+ QuadTweener(float a = 1.0f) { _a=a; }
+ virtual float Tween(float time, float start, float change, float duration)
+ {
+ switch (m_tweenerType)
+ {
+ case EASE_IN:
+ time /= duration;
+ return change * time * (_a * time + 1 - _a) + start;
+ break;
+
+ case EASE_OUT:
+ time /= duration;
+ return -change * time * (_a * time - 1 - _a) + start;
+ break;
+
+ case EASE_INOUT:
+ time /= duration/2;
+ if (time < 1)
+ return (change) * time * (_a * time + 1 - _a) + start;
+ time--;
+ return (-change) * time * (_a * time - 1 - _a) + start;
+ break;
+ }
+ return change * time * time + start;
+ }
+private:
+ float _a;
+};
+
+
+class CubicTweener : public Tweener
+{
+public:
+ virtual float Tween(float time, float start, float change, float duration)
+ {
+ switch (m_tweenerType)
+ {
+ case EASE_IN:
+ time /= duration;
+ return change * time * time * time + start;
+ break;
+
+ case EASE_OUT:
+ time /= duration;
+ time--;
+ return change * (time * time * time + 1) + start;
+ break;
+
+ case EASE_INOUT:
+ time /= duration/2;
+ if (time < 1)
+ return (change/2) * time * time * time + start;
+ time-=2;
+ return (change/2) * (time * time * time + 2) + start;
+ break;
+ }
+ return change * time * time + start;
+ }
+};
+
+class CircleTweener : public Tweener
+{
+public:
+ virtual float Tween(float time, float start, float change, float duration)
+ {
+ switch (m_tweenerType)
+ {
+ case EASE_IN:
+ time /= duration;
+ return (-change) * (sqrt(1 - time * time) - 1) + start;
+ break;
+
+ case EASE_OUT:
+ time /= duration;
+ time--;
+ return change * sqrt(1 - time * time) + start;
+ break;
+
+ case EASE_INOUT:
+ time /= duration/2;
+ if (time < 1)
+ return (-change/2) * (sqrt(1 - time * time) - 1) + start;
+ time-=2;
+ return change/2 * (sqrt(1 - time * time) + 1) + start;
+ break;
+ }
+ return change * sqrt(1 - time * time) + start;
+ }
+};
+
+class BackTweener : public Tweener
+{
+public:
+ BackTweener(float s=1.70158) { _s=s; }
+
+ virtual float Tween(float time, float start, float change, float duration)
+ {
+ float s = _s;
+ switch (m_tweenerType)
+ {
+ case EASE_IN:
+ time /= duration;
+ return change * time * time * ((s + 1) * time - s) + start;
+ break;
+
+ case EASE_OUT:
+ time /= duration;
+ time--;
+ return change * (time * time * ((s + 1) * time + s) + 1) + start;
+ break;
+
+ case EASE_INOUT:
+ time /= duration/2;
+ s*=(1.525f);
+ if ((time ) < 1)
+ {
+ return (change/2) * (time * time * ((s + 1) * time - s)) + start;
+ }
+ time-=2;
+ return (change/2) * (time * time * ((s + 1) * time + s) + 2) + start;
+ break;
+ }
+ return change * ((time-1) * time * ((s + 1) * time + s) + 1) + start;
+ }
+
+private:
+ float _s;
+
+};
+
+
+class SineTweener : public Tweener
+{
+public:
+ virtual float Tween(float time, float start, float change, float duration)
+ {
+ time /= duration;
+ switch (m_tweenerType)
+ {
+ case EASE_IN:
+ return change * (1 - cos(time * M_PI / 2.0f)) + start;
+ break;
+
+ case EASE_OUT:
+ return change * sin(time * M_PI / 2.0f) + start;
+ break;
+
+ case EASE_INOUT:
+ return change/2 * (1 - cos(M_PI * time)) + start;
+ break;
+ }
+ return (change/2) * (1 - cos(M_PI * time)) + start;
+ }
+};
+
+
+class BounceTweener : public Tweener
+{
+public:
+ virtual float Tween(float time, float start, float change, float duration)
+ {
+ switch (m_tweenerType)
+ {
+ case EASE_IN:
+ return (change - easeOut(duration - time, 0, change, duration)) + start;
+ break;
+
+ case EASE_OUT:
+ return easeOut(time, start, change, duration);
+ break;
+
+ case EASE_INOUT:
+ if (time < duration/2)
+ return (change - easeOut (duration - (time * 2), 0, change, duration) + start) * .5f + start;
+ else
+ return (easeOut (time * 2 - duration, 0, change, duration) * .5f + change * .5f) + start;
+ break;
+ }
+
+ return easeOut(time, start, change, duration);
+ }
+
+protected:
+ float easeOut(float time, float start, float change, float duration)
+ {
+ time /= duration;
+ if (time < (1/2.75)) {
+ return change * (7.5625f * time * time) + start;
+ } else if (time < (2/2.75)) {
+ time -= (1.5f/2.75f);
+ return change * (7.5625f * time * time + .75f) + start;
+ } else if (time < (2.5/2.75)) {
+ time -= (2.25f/2.75f);
+ return change * (7.5625f * time * time + .9375f) + start;
+ } else {
+ time -= (2.625f/2.75f);
+ return change * (7.5625f * time * time + .984375f) + start;
+ }
+ }
+};
+
+
+class ElasticTweener : public Tweener
+{
+public:
+ ElasticTweener(float a=0.0, float p=0.0) { _a=a; _p=p; }
+
+ virtual float Tween(float time, float start, float change, float duration)
+ {
+ switch (m_tweenerType)
+ {
+ case EASE_IN:
+ return easeIn(time, start, change, duration);
+ break;
+
+ case EASE_OUT:
+ return easeOut(time, start, change, duration);
+ break;
+
+ case EASE_INOUT:
+ return easeInOut(time, start, change, duration);
+ break;
+ }
+ return easeOut(time, start, change, duration);
+ }
+
+protected:
+ float _a;
+ float _p;
+
+ float easeIn(float time, float start, float change, float duration)
+ {
+ float s=0;
+ float a=_a;
+ float p=_p;
+
+ if (time==0)
+ return start;
+ time /= duration;
+ if (time==1)
+ return start + change;
+ if (!p)
+ p=duration*.3f;
+ if (!a || a < fabs(change))
+ {
+ a = change;
+ s = p / 4.0f;
+ }
+ else
+ {
+ s = p / (2 * M_PI) * asin (change / a);
+ }
+ time--;
+ return -(a * pow(2.0f, 10*time) * sin((time * duration - s) * (2 * M_PI) / p )) + start;
+ }
+
+ float easeOut(float time, float start, float change, float duration)
+ {
+ float s=0;
+ float a=_a;
+ float p=_p;
+
+ if (time==0)
+ return start;
+ time /= duration;
+ if (time==1)
+ return start + change;
+ if (!p)
+ p=duration*.3f;
+ if (!a || a < fabs(change))
+ {
+ a = change;
+ s = p / 4.0f;
+ }
+ else
+ {
+ s = p / (2 * M_PI) * asin (change / a);
+ }
+ return (a * pow(2.0f, -10*time) * sin((time * duration - s) * (2 * M_PI) / p )) + change + start;
+ }
+
+ float easeInOut(float time, float start, float change, float duration)
+ {
+ float s=0;
+ float a=_a;
+ float p=_p;
+
+ if (time==0)
+ return start;
+ time /= duration/2;
+ if (time==2)
+ return start + change;
+ if (!p)
+ p=duration*.3f*1.5f;
+ if (!a || a < fabs(change))
+ {
+ a = change;
+ s = p / 4.0f;
+ }
+ else
+ {
+ s = p / (2 * M_PI) * asin (change / a);
+ }
+
+ if (time < 1)
+ {
+ time--;
+ return -.5f * (a * pow(2.0f, 10 * (time)) * sin((time * duration - s) * (2 * M_PI) / p )) + start;
+ }
+ time--;
+ return a * pow(2.0f, -10 * (time)) * sin((time * duration-s) * (2 * M_PI) / p ) * .5f + change + start;
+ }
+};
+
+
+
+#endif // __TWEEN_H__
diff --git a/guilib/VisibleEffect.cpp b/guilib/VisibleEffect.cpp
new file mode 100644
index 0000000000..df48066142
--- /dev/null
+++ b/guilib/VisibleEffect.cpp
@@ -0,0 +1,703 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "VisibleEffect.h"
+#include "utils/GUIInfoManager.h"
+#include "utils/log.h"
+#include "SkinInfo.h" // for the effect time adjustments
+#include "StringUtils.h"
+#include "GUIImage.h" // for FRECT
+#include "Tween.h"
+#include "tinyXML/tinyxml.h"
+
+using namespace std;
+
+CAnimEffect::CAnimEffect(const TiXmlElement *node, EFFECT_TYPE effect)
+{
+ m_effect = effect;
+ // defaults
+ m_delay = m_length = 0;
+ m_pTweener = NULL;
+ // time and delay
+
+ float temp;
+ if (g_SkinInfo.ResolveConstant(node->Attribute("time"), temp)) m_length = (unsigned int)(temp * g_SkinInfo.GetEffectsSlowdown());
+ if (g_SkinInfo.ResolveConstant(node->Attribute("delay"), temp)) m_delay = (unsigned int)(temp * g_SkinInfo.GetEffectsSlowdown());
+
+ const char *tween = node->Attribute("tween");
+ if (tween)
+ {
+ if (strcmpi(tween, "linear")==0)
+ m_pTweener = new LinearTweener();
+ else if (strcmpi(tween, "quadratic")==0)
+ m_pTweener = new QuadTweener();
+ else if (strcmpi(tween, "cubic")==0)
+ m_pTweener = new CubicTweener();
+ else if (strcmpi(tween, "sine")==0)
+ m_pTweener = new SineTweener();
+ else if (strcmpi(tween, "back")==0)
+ m_pTweener = new BackTweener();
+ else if (strcmpi(tween, "circle")==0)
+ m_pTweener = new CircleTweener();
+ else if (strcmpi(tween, "bounce")==0)
+ m_pTweener = new BounceTweener();
+ else if (strcmpi(tween, "elastic")==0)
+ m_pTweener = new ElasticTweener();
+
+ const char *easing = node->Attribute("easing");
+ if (m_pTweener && easing)
+ {
+ if (strcmpi(easing, "in")==0)
+ m_pTweener->SetEasing(EASE_IN);
+ else if (strcmpi(easing, "out")==0)
+ m_pTweener->SetEasing(EASE_OUT);
+ else if (strcmpi(easing, "inout")==0)
+ m_pTweener->SetEasing(EASE_INOUT);
+ }
+ }
+
+ float accel;
+ g_SkinInfo.ResolveConstant(node->Attribute("acceleration"), accel);
+
+ if (!m_pTweener)
+ { // no tweener is specified - use a linear tweener
+ // or quadratic if we have acceleration
+ if (accel)
+ {
+ m_pTweener = new QuadTweener(accel);
+ m_pTweener->SetEasing(EASE_IN);
+ }
+ else
+ m_pTweener = new LinearTweener();
+ }
+}
+
+CAnimEffect::CAnimEffect(unsigned int delay, unsigned int length, EFFECT_TYPE effect)
+{
+ m_delay = delay;
+ m_length = length;
+ m_effect = effect;
+ m_pTweener = new LinearTweener();
+}
+
+CAnimEffect::~CAnimEffect()
+{
+ if (m_pTweener)
+ m_pTweener->Free();
+}
+
+CAnimEffect::CAnimEffect(const CAnimEffect &src)
+{
+ m_pTweener = NULL;
+ *this = src;
+}
+
+const CAnimEffect &CAnimEffect::operator=(const CAnimEffect &src)
+{
+ if (&src == this) return *this;
+
+ m_matrix = src.m_matrix;
+ m_effect = src.m_effect;
+ m_length = src.m_length;
+ m_delay = src.m_delay;
+
+ if (m_pTweener)
+ m_pTweener->Free();
+ m_pTweener = src.m_pTweener;
+ if (m_pTweener)
+ m_pTweener->IncRef();
+ return *this;
+}
+
+void CAnimEffect::Calculate(unsigned int time, const CPoint &center)
+{
+ assert(m_delay + m_length);
+ // calculate offset and tweening
+ float offset = 0.0f; // delayed forward, or finished reverse
+ if (time >= m_delay && time < m_delay + m_length)
+ offset = (float)(time - m_delay) / m_length;
+ else if (time >= m_delay + m_length)
+ offset = 1.0f;
+ if (m_pTweener)
+ offset = m_pTweener->Tween(offset, 0.0f, 1.0f, 1.0f);
+ // and apply the effect
+ ApplyEffect(offset, center);
+}
+
+void CAnimEffect::ApplyState(ANIMATION_STATE state, const CPoint &center)
+{
+ float offset = (state == ANIM_STATE_APPLIED) ? 1.0f : 0.0f;
+ ApplyEffect(offset, center);
+}
+
+CFadeEffect::CFadeEffect(const TiXmlElement *node, bool reverseDefaults) : CAnimEffect(node, EFFECT_TYPE_FADE)
+{
+ if (reverseDefaults)
+ { // out effect defaults
+ m_startAlpha = 100.0f;
+ m_endAlpha = 0;
+ }
+ else
+ { // in effect defaults
+ m_startAlpha = 0;
+ m_endAlpha = 100.0f;
+ }
+ if (node->Attribute("start")) g_SkinInfo.ResolveConstant(node->Attribute("start"), m_startAlpha);
+ if (node->Attribute("end")) g_SkinInfo.ResolveConstant(node->Attribute("end"), m_endAlpha);
+ if (m_startAlpha > 100.0f) m_startAlpha = 100.0f;
+ if (m_endAlpha > 100.0f) m_endAlpha = 100.0f;
+ if (m_startAlpha < 0) m_startAlpha = 0;
+ if (m_endAlpha < 0) m_endAlpha = 0;
+}
+
+CFadeEffect::CFadeEffect(float start, float end, unsigned int delay, unsigned int length) : CAnimEffect(delay, length, EFFECT_TYPE_FADE)
+{
+ m_startAlpha = start;
+ m_endAlpha = end;
+}
+
+void CFadeEffect::ApplyEffect(float offset, const CPoint &center)
+{
+ m_matrix.SetFader(((m_endAlpha - m_startAlpha) * offset + m_startAlpha) * 0.01f);
+}
+
+CSlideEffect::CSlideEffect(const TiXmlElement *node) : CAnimEffect(node, EFFECT_TYPE_SLIDE)
+{
+ m_startX = m_endX = 0;
+ m_startY = m_endY = 0;
+ const char *startPos = node->Attribute("start");
+ if (startPos)
+ {
+ vector<CStdString> commaSeparated;
+ StringUtils::SplitString(startPos, ",", commaSeparated);
+ if (commaSeparated.size() > 1)
+ g_SkinInfo.ResolveConstant(commaSeparated[1], m_startY);
+ g_SkinInfo.ResolveConstant(commaSeparated[0], m_startX);
+ }
+ const char *endPos = node->Attribute("end");
+ if (endPos)
+ {
+ vector<CStdString> commaSeparated;
+ StringUtils::SplitString(endPos, ",", commaSeparated);
+ if (commaSeparated.size() > 1)
+ g_SkinInfo.ResolveConstant(commaSeparated[1], m_endY);
+ g_SkinInfo.ResolveConstant(commaSeparated[0], m_endX);
+ }
+}
+
+void CSlideEffect::ApplyEffect(float offset, const CPoint &center)
+{
+ m_matrix.SetTranslation((m_endX - m_startX)*offset + m_startX, (m_endY - m_startY)*offset + m_startY, 0);
+}
+
+CRotateEffect::CRotateEffect(const TiXmlElement *node, EFFECT_TYPE effect) : CAnimEffect(node, effect)
+{
+ m_startAngle = m_endAngle = 0;
+ m_autoCenter = false;
+ if (node->Attribute("start")) g_SkinInfo.ResolveConstant(node->Attribute("start"), m_startAngle);
+ if (node->Attribute("end")) g_SkinInfo.ResolveConstant(node->Attribute("end"), m_endAngle);
+
+ // convert to a negative to account for our reversed Y axis (Needed for X and Z ???)
+ m_startAngle *= -1;
+ m_endAngle *= -1;
+
+ const char *centerPos = node->Attribute("center");
+ if (centerPos)
+ {
+ if (strcmpi(centerPos, "auto") == 0)
+ m_autoCenter = true;
+ else
+ {
+ vector<CStdString> commaSeparated;
+ StringUtils::SplitString(centerPos, ",", commaSeparated);
+ if (commaSeparated.size() > 1)
+ g_SkinInfo.ResolveConstant(commaSeparated[1], m_center.y);
+ g_SkinInfo.ResolveConstant(commaSeparated[0], m_center.x);
+ }
+ }
+}
+
+void CRotateEffect::ApplyEffect(float offset, const CPoint &center)
+{
+ static const float degree_to_radian = 0.01745329252f;
+ if (m_autoCenter)
+ m_center = center;
+ if (m_effect == EFFECT_TYPE_ROTATE_X)
+ m_matrix.SetXRotation(((m_endAngle - m_startAngle)*offset + m_startAngle) * degree_to_radian, m_center.x, m_center.y, 1.0f);
+ else if (m_effect == EFFECT_TYPE_ROTATE_Y)
+ m_matrix.SetYRotation(((m_endAngle - m_startAngle)*offset + m_startAngle) * degree_to_radian, m_center.x, m_center.y, 1.0f);
+ else if (m_effect == EFFECT_TYPE_ROTATE_Z) // note coordinate aspect ratio is not generally square in the XY plane, so correct for it.
+ m_matrix.SetZRotation(((m_endAngle - m_startAngle)*offset + m_startAngle) * degree_to_radian, m_center.x, m_center.y, g_graphicsContext.GetScalingPixelRatio());
+}
+
+CZoomEffect::CZoomEffect(const TiXmlElement *node, const FRECT &rect) : CAnimEffect(node, EFFECT_TYPE_ZOOM)
+{
+ // effect defaults
+ m_startX = m_startY = 100;
+ m_endX = m_endY = 100;
+ m_center = CPoint(0,0);
+ m_autoCenter = false;
+
+ float startPosX = rect.left;
+ float startPosY = rect.top;
+ float endPosX = rect.left;
+ float endPosY = rect.top;
+
+ float width = (rect.right) ? rect.right : 0.001f;
+ float height = (rect.bottom) ? rect.bottom : 0.001f;
+
+ const char *start = node->Attribute("start");
+ if (start)
+ {
+ CStdStringArray params;
+ StringUtils::SplitString(start, ",", params);
+ if (params.size() == 1)
+ {
+ g_SkinInfo.ResolveConstant(params[0], m_startX);
+ m_startY = m_startX;
+ }
+ else if (params.size() == 2)
+ {
+ g_SkinInfo.ResolveConstant(params[0], m_startX);
+ g_SkinInfo.ResolveConstant(params[1], m_startY);
+ }
+ else if (params.size() == 4)
+ { // format is start="x,y,width,height"
+ // use width and height from our rect to calculate our sizing
+ g_SkinInfo.ResolveConstant(params[0], startPosX);
+ g_SkinInfo.ResolveConstant(params[1], startPosY);
+ g_SkinInfo.ResolveConstant(params[2], m_startX);
+ g_SkinInfo.ResolveConstant(params[3], m_startY);
+ m_startX *= 100.0f / width;
+ m_startY *= 100.0f / height;
+ }
+ }
+ const char *end = node->Attribute("end");
+ if (end)
+ {
+ CStdStringArray params;
+ StringUtils::SplitString(end, ",", params);
+ if (params.size() == 1)
+ {
+ g_SkinInfo.ResolveConstant(params[0], m_endX);
+ m_endY = m_endX;
+ }
+ else if (params.size() == 2)
+ {
+ g_SkinInfo.ResolveConstant(params[0], m_endX);
+ g_SkinInfo.ResolveConstant(params[1], m_endY);
+ }
+ else if (params.size() == 4)
+ { // format is start="x,y,width,height"
+ // use width and height from our rect to calculate our sizing
+ g_SkinInfo.ResolveConstant(params[0], endPosX);
+ g_SkinInfo.ResolveConstant(params[1], endPosY);
+ g_SkinInfo.ResolveConstant(params[2], m_endX);
+ g_SkinInfo.ResolveConstant(params[3], m_endY);
+ m_endX *= 100.0f / width;
+ m_endY *= 100.0f / height;
+ }
+ }
+ const char *centerPos = node->Attribute("center");
+ if (centerPos)
+ {
+ if (strcmpi(centerPos, "auto") == 0)
+ m_autoCenter = true;
+ else
+ {
+ vector<CStdString> commaSeparated;
+ StringUtils::SplitString(centerPos, ",", commaSeparated);
+ if (commaSeparated.size() > 1)
+ g_SkinInfo.ResolveConstant(commaSeparated[1], m_center.y);
+ g_SkinInfo.ResolveConstant(commaSeparated[0], m_center.x);
+ }
+ }
+ else
+ { // no center specified
+ // calculate the center position...
+ if (m_startX)
+ {
+ float scale = m_endX / m_startX;
+ if (scale != 1)
+ m_center.x = (endPosX - scale*startPosX) / (1 - scale);
+ }
+ if (m_startY)
+ {
+ float scale = m_endY / m_startY;
+ if (scale != 1)
+ m_center.y = (endPosY - scale*startPosY) / (1 - scale);
+ }
+ }
+}
+
+void CZoomEffect::ApplyEffect(float offset, const CPoint &center)
+{
+ if (m_autoCenter)
+ m_center = center;
+ float scaleX = ((m_endX - m_startX)*offset + m_startX) * 0.01f;
+ float scaleY = ((m_endY - m_startY)*offset + m_startY) * 0.01f;
+ m_matrix.SetScaler(scaleX, scaleY, m_center.x, m_center.y);
+}
+
+CAnimation::CAnimation()
+{
+ m_type = ANIM_TYPE_NONE;
+ m_reversible = true;
+ m_condition = 0;
+ m_repeatAnim = ANIM_REPEAT_NONE;
+ m_currentState = ANIM_STATE_NONE;
+ m_currentProcess = ANIM_PROCESS_NONE;
+ m_queuedProcess = ANIM_PROCESS_NONE;
+ m_lastCondition = false;
+ m_length = 0;
+ m_delay = 0;
+ m_start = 0;
+ m_amount = 0;
+}
+
+CAnimation::CAnimation(const CAnimation &src)
+{
+ *this = src;
+}
+
+CAnimation::~CAnimation()
+{
+ for (unsigned int i = 0; i < m_effects.size(); i++)
+ delete m_effects[i];
+ m_effects.clear();
+}
+
+const CAnimation &CAnimation::operator =(const CAnimation &src)
+{
+ if (this == &src) return *this; // same
+ m_type = src.m_type;
+ m_reversible = src.m_reversible;
+ m_condition = src.m_condition;
+ m_repeatAnim = src.m_repeatAnim;
+ m_lastCondition = src.m_lastCondition;
+ m_queuedProcess = src.m_queuedProcess;
+ m_currentProcess = src.m_currentProcess;
+ m_currentState = src.m_currentState;
+ m_start = src.m_start;
+ m_length = src.m_length;
+ m_delay = src.m_delay;
+ m_amount = src.m_amount;
+ // clear all our effects
+ for (unsigned int i = 0; i < m_effects.size(); i++)
+ delete m_effects[i];
+ m_effects.clear();
+ // and assign the others across
+ for (unsigned int i = 0; i < src.m_effects.size(); i++)
+ {
+ CAnimEffect *newEffect = NULL;
+ if (src.m_effects[i]->GetType() == CAnimEffect::EFFECT_TYPE_FADE)
+ newEffect = new CFadeEffect(*(CFadeEffect *)src.m_effects[i]);
+ else if (src.m_effects[i]->GetType() == CAnimEffect::EFFECT_TYPE_ZOOM)
+ newEffect = new CZoomEffect(*(CZoomEffect *)src.m_effects[i]);
+ else if (src.m_effects[i]->GetType() == CAnimEffect::EFFECT_TYPE_SLIDE)
+ newEffect = new CSlideEffect(*(CSlideEffect *)src.m_effects[i]);
+ else if (src.m_effects[i]->GetType() == CAnimEffect::EFFECT_TYPE_ROTATE_X ||
+ src.m_effects[i]->GetType() == CAnimEffect::EFFECT_TYPE_ROTATE_Y ||
+ src.m_effects[i]->GetType() == CAnimEffect::EFFECT_TYPE_ROTATE_Z)
+ newEffect = new CRotateEffect(*(CRotateEffect *)src.m_effects[i]);
+ if (newEffect)
+ m_effects.push_back(newEffect);
+ }
+ return *this;
+}
+
+void CAnimation::Animate(unsigned int time, bool startAnim)
+{
+ // First start any queued animations
+ if (m_queuedProcess == ANIM_PROCESS_NORMAL)
+ {
+ if (m_currentProcess == ANIM_PROCESS_REVERSE)
+ m_start = time - m_amount; // reverse direction of animation
+ else
+ m_start = time;
+ m_currentProcess = ANIM_PROCESS_NORMAL;
+ }
+ else if (m_queuedProcess == ANIM_PROCESS_REVERSE)
+ {
+ if (m_currentProcess == ANIM_PROCESS_NORMAL)
+ m_start = time - (m_length - m_amount); // reverse direction of animation
+ else if (m_currentProcess == ANIM_PROCESS_NONE)
+ m_start = time;
+ m_currentProcess = ANIM_PROCESS_REVERSE;
+ }
+ // reset the queued state once we've rendered to ensure allocation has occured
+ if (startAnim || m_queuedProcess == ANIM_PROCESS_REVERSE)
+ m_queuedProcess = ANIM_PROCESS_NONE;
+
+ // Update our animation process
+ if (m_currentProcess == ANIM_PROCESS_NORMAL)
+ {
+ if (time - m_start < m_delay)
+ {
+ m_amount = 0;
+ m_currentState = ANIM_STATE_DELAYED;
+ }
+ else if (time - m_start < m_length + m_delay)
+ {
+ m_amount = time - m_start - m_delay;
+ m_currentState = ANIM_STATE_IN_PROCESS;
+ }
+ else
+ {
+ m_amount = m_length;
+ if (m_repeatAnim == ANIM_REPEAT_PULSE && m_lastCondition)
+ { // pulsed anims auto-reverse
+ m_currentProcess = ANIM_PROCESS_REVERSE;
+ m_start = time;
+ }
+ else if (m_repeatAnim == ANIM_REPEAT_LOOP && m_lastCondition)
+ { // looped anims start over
+ m_amount = 0;
+ m_start = time;
+ }
+ else
+ m_currentState = ANIM_STATE_APPLIED;
+ }
+ }
+ else if (m_currentProcess == ANIM_PROCESS_REVERSE)
+ {
+ if (time - m_start < m_length)
+ {
+ m_amount = m_length - (time - m_start);
+ m_currentState = ANIM_STATE_IN_PROCESS;
+ }
+ else
+ {
+ m_amount = 0;
+ if (m_repeatAnim == ANIM_REPEAT_PULSE && m_lastCondition)
+ { // pulsed anims auto-reverse
+ m_currentProcess = ANIM_PROCESS_NORMAL;
+ m_start = time;
+ }
+ else
+ m_currentState = ANIM_STATE_APPLIED;
+ }
+ }
+}
+
+void CAnimation::ResetAnimation()
+{
+ m_queuedProcess = ANIM_PROCESS_NONE;
+ m_currentProcess = ANIM_PROCESS_NONE;
+ m_currentState = ANIM_STATE_NONE;
+}
+
+void CAnimation::ApplyAnimation()
+{
+ m_queuedProcess = ANIM_PROCESS_NONE;
+ if (m_repeatAnim == ANIM_REPEAT_PULSE)
+ { // pulsed anims auto-reverse
+ m_amount = m_length;
+ m_currentProcess = ANIM_PROCESS_REVERSE;
+ m_currentState = ANIM_STATE_IN_PROCESS;
+ }
+ else if (m_repeatAnim == ANIM_REPEAT_LOOP)
+ { // looped anims start over
+ m_amount = 0;
+ m_currentProcess = ANIM_PROCESS_NORMAL;
+ m_currentState = ANIM_STATE_IN_PROCESS;
+ }
+ else
+ { // set normal process, so that Calculate() knows that we're finishing for zero length effects
+ // it will be reset in RenderAnimation()
+ m_currentProcess = ANIM_PROCESS_NORMAL;
+ m_currentState = ANIM_STATE_APPLIED;
+ m_amount = m_length;
+ }
+ Calculate(CPoint());
+}
+
+void CAnimation::Calculate(const CPoint &center)
+{
+ for (unsigned int i = 0; i < m_effects.size(); i++)
+ {
+ CAnimEffect *effect = m_effects[i];
+ if (effect->GetLength())
+ effect->Calculate(m_delay + m_amount, center);
+ else
+ { // effect has length zero, so either apply complete
+ if (m_currentProcess == ANIM_PROCESS_NORMAL)
+ effect->ApplyState(ANIM_STATE_APPLIED, center);
+ else
+ effect->ApplyState(ANIM_STATE_NONE, center);
+ }
+ }
+}
+
+void CAnimation::RenderAnimation(TransformMatrix &matrix, const CPoint &center)
+{
+ if (m_currentProcess != ANIM_PROCESS_NONE)
+ Calculate(center);
+ // If we have finished an animation, reset the animation state
+ // We do this here (rather than in Animate()) as we need the
+ // currentProcess information in the UpdateStates() function of the
+ // window and control classes.
+ if (m_currentState == ANIM_STATE_APPLIED)
+ {
+ m_currentProcess = ANIM_PROCESS_NONE;
+ m_queuedProcess = ANIM_PROCESS_NONE;
+ }
+ if (m_currentState != ANIM_STATE_NONE)
+ {
+ for (unsigned int i = 0; i < m_effects.size(); i++)
+ matrix *= m_effects[i]->GetTransform();
+ }
+}
+
+void CAnimation::QueueAnimation(ANIMATION_PROCESS process)
+{
+ m_queuedProcess = process;
+}
+
+CAnimation *CAnimation::CreateFader(float start, float end, unsigned int delay, unsigned int length)
+{
+ CAnimation *anim = new CAnimation();
+ if (anim)
+ {
+ CFadeEffect *effect = new CFadeEffect(start, end, delay, length);
+ if (effect)
+ anim->AddEffect(effect);
+ }
+ return anim;
+}
+
+void CAnimation::UpdateCondition(int contextWindow, const CGUIListItem *item)
+{
+ bool condition = g_infoManager.GetBool(m_condition, contextWindow, item);
+ if (condition && !m_lastCondition)
+ QueueAnimation(ANIM_PROCESS_NORMAL);
+ else if (!condition && m_lastCondition)
+ {
+ if (m_reversible)
+ QueueAnimation(ANIM_PROCESS_REVERSE);
+ else
+ ResetAnimation();
+ }
+ m_lastCondition = condition;
+}
+
+void CAnimation::SetInitialCondition(int contextWindow)
+{
+ m_lastCondition = g_infoManager.GetBool(m_condition, contextWindow);
+ if (m_lastCondition)
+ ApplyAnimation();
+ else
+ ResetAnimation();
+}
+
+void CAnimation::Create(const TiXmlElement *node, const FRECT &rect)
+{
+ if (!node || !node->FirstChild())
+ return;
+
+ // conditions and reversibility
+ const char *condition = node->Attribute("condition");
+ if (condition)
+ m_condition = g_infoManager.TranslateString(condition);
+ const char *reverse = node->Attribute("reversible");
+ if (reverse && strcmpi(reverse, "false") == 0)
+ m_reversible = false;
+
+ const TiXmlElement *effect = node->FirstChildElement("effect");
+
+ CStdString type = node->FirstChild()->Value();
+ m_type = ANIM_TYPE_CONDITIONAL;
+ if (effect) // new layout
+ type = node->Attribute("type");
+
+ if (type.Left(7).Equals("visible")) m_type = ANIM_TYPE_VISIBLE;
+ else if (type.Equals("hidden")) m_type = ANIM_TYPE_HIDDEN;
+ else if (type.Equals("focus")) m_type = ANIM_TYPE_FOCUS;
+ else if (type.Equals("unfocus")) m_type = ANIM_TYPE_UNFOCUS;
+ else if (type.Equals("windowopen")) m_type = ANIM_TYPE_WINDOW_OPEN;
+ else if (type.Equals("windowclose")) m_type = ANIM_TYPE_WINDOW_CLOSE;
+ // sanity check
+ if (m_type == ANIM_TYPE_CONDITIONAL)
+ {
+ if (!m_condition)
+ {
+ CLog::Log(LOGERROR, "Control has invalid animation type (no condition or no type)");
+ return;
+ }
+
+ // pulsed or loop animations
+ const char *pulse = node->Attribute("pulse");
+ if (pulse && strcmpi(pulse, "true") == 0)
+ m_repeatAnim = ANIM_REPEAT_PULSE;
+ const char *loop = node->Attribute("loop");
+ if (loop && strcmpi(loop, "true") == 0)
+ m_repeatAnim = ANIM_REPEAT_LOOP;
+ }
+
+ m_delay = 0xffffffff;
+ if (!effect)
+ { // old layout:
+ // <animation effect="fade" start="0" end="100" delay="10" time="2000" condition="blahdiblah" reversible="false">focus</animation>
+ CStdString type = node->Attribute("effect");
+ AddEffect(type, node, rect);
+ }
+ while (effect)
+ { // new layout:
+ // <animation type="focus" condition="blahdiblah" reversible="false">
+ // <effect type="fade" start="0" end="100" delay="10" time="2000" />
+ // ...
+ // </animation>
+ CStdString type = effect->Attribute("type");
+ AddEffect(type, effect, rect);
+ effect = effect->NextSiblingElement("effect");
+ }
+}
+
+void CAnimation::AddEffect(const CStdString &type, const TiXmlElement *node, const FRECT &rect)
+{
+ CAnimEffect *effect = NULL;
+ if (type.Equals("fade"))
+ effect = new CFadeEffect(node, m_type < 0);
+ else if (type.Equals("slide"))
+ effect = new CSlideEffect(node);
+ else if (type.Equals("rotate"))
+ effect = new CRotateEffect(node, CAnimEffect::EFFECT_TYPE_ROTATE_Z);
+ else if (type.Equals("rotatey"))
+ effect = new CRotateEffect(node, CAnimEffect::EFFECT_TYPE_ROTATE_Y);
+ else if (type.Equals("rotatex"))
+ effect = new CRotateEffect(node, CAnimEffect::EFFECT_TYPE_ROTATE_X);
+ else if (type.Equals("zoom"))
+ effect = new CZoomEffect(node, rect);
+
+ if (effect)
+ AddEffect(effect);
+}
+
+void CAnimation::AddEffect(CAnimEffect *effect)
+{
+ m_effects.push_back(effect);
+ // our delay is the minimum of all the effect delays
+ if (effect->GetDelay() < m_delay)
+ m_delay = effect->GetDelay();
+ // our length is the maximum of all the effect lengths
+ if (effect->GetLength() > m_delay + m_length)
+ m_length = effect->GetLength() - m_delay;
+}
diff --git a/guilib/VisibleEffect.h b/guilib/VisibleEffect.h
new file mode 100644
index 0000000000..6786f1f473
--- /dev/null
+++ b/guilib/VisibleEffect.h
@@ -0,0 +1,205 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+enum ANIMATION_PROCESS { ANIM_PROCESS_NONE = 0, ANIM_PROCESS_NORMAL, ANIM_PROCESS_REVERSE };
+enum ANIMATION_STATE { ANIM_STATE_NONE = 0, ANIM_STATE_DELAYED, ANIM_STATE_IN_PROCESS, ANIM_STATE_APPLIED };
+
+// forward definitions
+
+class TiXmlElement;
+class Tweener;
+struct FRECT;
+class CGUIListItem;
+
+#include "TransformMatrix.h" // needed for the TransformMatrix member
+#include "Geometry.h" // for CPoint
+#include "StdString.h"
+
+enum ANIMATION_TYPE
+{
+ ANIM_TYPE_UNFOCUS = -3,
+ ANIM_TYPE_HIDDEN,
+ ANIM_TYPE_WINDOW_CLOSE,
+ ANIM_TYPE_NONE,
+ ANIM_TYPE_WINDOW_OPEN,
+ ANIM_TYPE_VISIBLE,
+ ANIM_TYPE_FOCUS,
+ ANIM_TYPE_CONDITIONAL // for animations triggered by a condition change
+};
+
+class CAnimEffect
+{
+public:
+ enum EFFECT_TYPE { EFFECT_TYPE_NONE = 0, EFFECT_TYPE_FADE, EFFECT_TYPE_SLIDE, EFFECT_TYPE_ROTATE_X, EFFECT_TYPE_ROTATE_Y, EFFECT_TYPE_ROTATE_Z, EFFECT_TYPE_ZOOM };
+
+ CAnimEffect(const TiXmlElement *node, EFFECT_TYPE effect);
+ CAnimEffect(unsigned int delay, unsigned int length, EFFECT_TYPE effect);
+ CAnimEffect(const CAnimEffect &src);
+
+ virtual ~CAnimEffect();
+ const CAnimEffect &operator=(const CAnimEffect &src);
+
+ void Calculate(unsigned int time, const CPoint &center);
+ void ApplyState(ANIMATION_STATE state, const CPoint &center);
+
+ unsigned int GetDelay() const { return m_delay; };
+ unsigned int GetLength() const { return m_delay + m_length; };
+ const TransformMatrix &GetTransform() const { return m_matrix; };
+ EFFECT_TYPE GetType() const { return m_effect; };
+
+protected:
+ TransformMatrix m_matrix;
+ EFFECT_TYPE m_effect;
+
+private:
+ virtual void ApplyEffect(float offset, const CPoint &center)=0;
+
+ // timing variables
+ unsigned int m_length;
+ unsigned int m_delay;
+
+ Tweener *m_pTweener;
+};
+
+class CFadeEffect : public CAnimEffect
+{
+public:
+ CFadeEffect(const TiXmlElement *node, bool reverseDefaults);
+ CFadeEffect(float start, float end, unsigned int delay, unsigned int length);
+ virtual ~CFadeEffect() {};
+private:
+ virtual void ApplyEffect(float offset, const CPoint &center);
+
+ float m_startAlpha;
+ float m_endAlpha;
+};
+
+class CSlideEffect : public CAnimEffect
+{
+public:
+ CSlideEffect(const TiXmlElement *node);
+ virtual ~CSlideEffect() {};
+private:
+ virtual void ApplyEffect(float offset, const CPoint &center);
+
+ float m_startX;
+ float m_startY;
+ float m_endX;
+ float m_endY;
+};
+
+class CRotateEffect : public CAnimEffect
+{
+public:
+ CRotateEffect(const TiXmlElement *node, EFFECT_TYPE effect);
+ virtual ~CRotateEffect() {};
+private:
+ virtual void ApplyEffect(float offset, const CPoint &center);
+
+ float m_startAngle;
+ float m_endAngle;
+
+ bool m_autoCenter;
+ CPoint m_center;
+};
+
+class CZoomEffect : public CAnimEffect
+{
+public:
+ CZoomEffect(const TiXmlElement *node, const FRECT &rect);
+ virtual ~CZoomEffect() {};
+private:
+ virtual void ApplyEffect(float offset, const CPoint &center);
+
+ float m_startX;
+ float m_startY;
+ float m_endX;
+ float m_endY;
+
+ bool m_autoCenter;
+ CPoint m_center;
+};
+
+class CAnimation
+{
+public:
+ CAnimation();
+ CAnimation(const CAnimation &src);
+
+ virtual ~CAnimation();
+
+ const CAnimation &operator=(const CAnimation &src);
+
+ static CAnimation *CreateFader(float start, float end, unsigned int delay, unsigned int length);
+
+ void Create(const TiXmlElement *node, const FRECT &rect);
+
+ void Animate(unsigned int time, bool startAnim);
+ void ResetAnimation();
+ void ApplyAnimation();
+ inline void RenderAnimation(TransformMatrix &matrix)
+ {
+ RenderAnimation(matrix, CPoint());
+ }
+ void RenderAnimation(TransformMatrix &matrix, const CPoint &center);
+ void QueueAnimation(ANIMATION_PROCESS process);
+
+ inline bool IsReversible() const { return m_reversible; };
+ inline int GetCondition() const { return m_condition; };
+ inline ANIMATION_TYPE GetType() const { return m_type; };
+ inline ANIMATION_STATE GetState() const { return m_currentState; };
+ inline ANIMATION_PROCESS GetProcess() const { return m_currentProcess; };
+ inline ANIMATION_PROCESS GetQueuedProcess() const { return m_queuedProcess; };
+
+ void UpdateCondition(int contextWindow, const CGUIListItem *item = NULL);
+ void SetInitialCondition(int contextWindow);
+
+private:
+ void Calculate(const CPoint &point);
+ void AddEffect(const CStdString &type, const TiXmlElement *node, const FRECT &rect);
+ void AddEffect(CAnimEffect *effect);
+
+ enum ANIM_REPEAT { ANIM_REPEAT_NONE = 0, ANIM_REPEAT_PULSE, ANIM_REPEAT_LOOP };
+
+ // type of animation
+ ANIMATION_TYPE m_type;
+ bool m_reversible;
+ int m_condition;
+
+ // conditional anims can repeat
+ ANIM_REPEAT m_repeatAnim;
+ bool m_lastCondition;
+
+ // state of animation
+ ANIMATION_PROCESS m_queuedProcess;
+ ANIMATION_PROCESS m_currentProcess;
+ ANIMATION_STATE m_currentState;
+
+ // timing of animation
+ unsigned int m_start;
+ unsigned int m_length;
+ unsigned int m_delay;
+ unsigned int m_amount;
+
+ std::vector<CAnimEffect *> m_effects;
+};
diff --git a/guilib/XMLUtils.cpp b/guilib/XMLUtils.cpp
new file mode 100644
index 0000000000..83cb226d55
--- /dev/null
+++ b/guilib/XMLUtils.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "XMLUtils.h"
+#include "Util.h"
+#include "FileSystem/SpecialProtocol.h"
+
+bool XMLUtils::GetHex(const TiXmlNode* pRootNode, const char* strTag, uint32_t& hexValue)
+{
+ const TiXmlNode* pNode = pRootNode->FirstChild(strTag );
+ if (!pNode || !pNode->FirstChild()) return false;
+ sscanf(pNode->FirstChild()->Value(), "%x", (uint32_t*) &hexValue );
+ return true;
+}
+
+
+bool XMLUtils::GetUInt(const TiXmlNode* pRootNode, const char* strTag, uint32_t& uintValue)
+{
+ const TiXmlNode* pNode = pRootNode->FirstChild(strTag );
+ if (!pNode || !pNode->FirstChild()) return false;
+ uintValue = atol(pNode->FirstChild()->Value());
+ return true;
+}
+
+bool XMLUtils::GetLong(const TiXmlNode* pRootNode, const char* strTag, long& lLongValue)
+{
+ const TiXmlNode* pNode = pRootNode->FirstChild(strTag );
+ if (!pNode || !pNode->FirstChild()) return false;
+ lLongValue = atol(pNode->FirstChild()->Value());
+ return true;
+}
+
+bool XMLUtils::GetInt(const TiXmlNode* pRootNode, const char* strTag, int& iIntValue)
+{
+ const TiXmlNode* pNode = pRootNode->FirstChild(strTag );
+ if (!pNode || !pNode->FirstChild()) return false;
+ iIntValue = atoi(pNode->FirstChild()->Value());
+ return true;
+}
+
+bool XMLUtils::GetInt(const TiXmlNode* pRootNode, const char* strTag, int &value, const int min, const int max)
+{
+ if (GetInt(pRootNode, strTag, value))
+ {
+ if (value < min) value = min;
+ if (value > max) value = max;
+ return true;
+ }
+ return false;
+}
+
+bool XMLUtils::GetFloat(const TiXmlNode* pRootNode, const char* strTag, float& value)
+{
+ const TiXmlNode* pNode = pRootNode->FirstChild(strTag );
+ if (!pNode || !pNode->FirstChild()) return false;
+ value = (float)atof(pNode->FirstChild()->Value());
+ return true;
+}
+
+bool XMLUtils::GetFloat(const TiXmlNode* pRootElement, const char *tagName, float& fValue, const float fMin, const float fMax)
+{
+ if (GetFloat(pRootElement, tagName, fValue))
+ { // check range
+ if (fValue < fMin) fValue = fMin;
+ if (fValue > fMax) fValue = fMax;
+ return true;
+ }
+ return false;
+}
+
+bool XMLUtils::GetBoolean(const TiXmlNode* pRootNode, const char* strTag, bool& bBoolValue)
+{
+ const TiXmlNode* pNode = pRootNode->FirstChild(strTag );
+ if (!pNode || !pNode->FirstChild()) return false;
+ CStdString strEnabled = pNode->FirstChild()->Value();
+ strEnabled.ToLower();
+ if (strEnabled == "off" || strEnabled == "no" || strEnabled == "disabled" || strEnabled == "false")
+ bBoolValue = false;
+ else
+ {
+ bBoolValue = true;
+ if (strEnabled != "on" && strEnabled != "yes" && strEnabled != "enabled" && strEnabled != "true")
+ return false; // invalid bool switch - it's probably some other string.
+ }
+ return true;
+}
+
+bool XMLUtils::GetString(const TiXmlNode* pRootNode, const char* strTag, CStdString& strStringValue)
+{
+ const TiXmlElement* pElement = pRootNode->FirstChildElement(strTag );
+ if (!pElement) return false;
+ const char* encoded = pElement->Attribute("urlencoded");
+ const TiXmlNode* pNode = pElement->FirstChild();
+ if (pNode != NULL)
+ {
+ strStringValue = pNode->Value();
+ if (encoded && stricmp(encoded,"yes") == 0)
+ CUtil::UrlDecode(strStringValue);
+ return true;
+ }
+ strStringValue.Empty();
+ return false;
+}
+
+bool XMLUtils::GetAdditiveString(const TiXmlNode* pRootNode, const char* strTag,
+ const CStdString& strSeparator, CStdString& strStringValue)
+{
+ CStdString strTemp;
+ const TiXmlElement* node = pRootNode->FirstChildElement(strTag);
+ bool bResult=false;
+ while (node)
+ {
+ if (node->FirstChild())
+ {
+ bResult = true;
+ strTemp = node->FirstChild()->Value();
+ const char* clear=node->Attribute("clear");
+ if (strStringValue.IsEmpty() || (clear && stricmp(clear,"true")==0))
+ strStringValue = strTemp;
+ else
+ strStringValue += strSeparator+strTemp;
+ }
+ node = node->NextSiblingElement(strTag);
+ }
+
+ return bResult;
+}
+
+/*!
+ Returns true if the encoding of the document is other then UTF-8.
+ /param strEncoding Returns the encoding of the document. Empty if UTF-8
+*/
+bool XMLUtils::GetEncoding(const TiXmlDocument* pDoc, CStdString& strEncoding)
+{
+ const TiXmlNode* pNode=NULL;
+ while ((pNode=pDoc->IterateChildren(pNode)) && pNode->Type()!=TiXmlNode::DECLARATION) {}
+ if (!pNode) return false;
+ const TiXmlDeclaration* pDecl=pNode->ToDeclaration();
+ if (!pDecl) return false;
+ strEncoding=pDecl->Encoding();
+ if (strEncoding.Equals("UTF-8") || strEncoding.Equals("UTF8")) strEncoding.Empty();
+ strEncoding.MakeUpper();
+ return !strEncoding.IsEmpty(); // Other encoding then UTF8?
+}
+
+/*!
+ Returns true if the encoding of the document is specified as as UTF-8
+ /param strXML The XML file (embedded in a string) to check.
+*/
+bool XMLUtils::HasUTF8Declaration(const CStdString &strXML)
+{
+ CStdString test = strXML;
+ test.ToLower();
+ // test for the encoding="utf-8" string
+ if (test.Find("encoding=\"utf-8\"") >= 0)
+ return true;
+ // TODO: test for plain UTF8 here?
+ return false;
+}
+
+bool XMLUtils::GetPath(const TiXmlNode* pRootNode, const char* strTag, CStdString& strStringValue)
+{
+ const TiXmlElement* pElement = pRootNode->FirstChildElement(strTag);
+ if (!pElement) return false;
+
+ int pathVersion = 0;
+ pElement->Attribute("pathversion", &pathVersion);
+ const char* encoded = pElement->Attribute("urlencoded");
+ const TiXmlNode* pNode = pElement->FirstChild();
+ if (pNode != NULL)
+ {
+ strStringValue = pNode->Value();
+ if (encoded && stricmp(encoded,"yes") == 0)
+ CUtil::UrlDecode(strStringValue);
+ strStringValue = CSpecialProtocol::ReplaceOldPath(strStringValue, pathVersion);
+ return true;
+ }
+ strStringValue.Empty();
+ return false;
+}
+
+void XMLUtils::SetString(TiXmlNode* pRootNode, const char *strTag, const CStdString& strValue)
+{
+ TiXmlElement newElement(strTag);
+ TiXmlNode *pNewNode = pRootNode->InsertEndChild(newElement);
+ if (pNewNode)
+ {
+ TiXmlText value(strValue);
+ pNewNode->InsertEndChild(value);
+ }
+}
+
+void XMLUtils::SetInt(TiXmlNode* pRootNode, const char *strTag, int value)
+{
+ CStdString strValue;
+ strValue.Format("%i", value);
+ SetString(pRootNode, strTag, strValue);
+}
+
+void XMLUtils::SetLong(TiXmlNode* pRootNode, const char *strTag, long value)
+{
+ CStdString strValue;
+ strValue.Format("%l", value);
+ SetString(pRootNode, strTag, strValue);
+}
+
+void XMLUtils::SetFloat(TiXmlNode* pRootNode, const char *strTag, float value)
+{
+ CStdString strValue;
+ strValue.Format("%f", value);
+ SetString(pRootNode, strTag, strValue);
+}
+
+void XMLUtils::SetBoolean(TiXmlNode* pRootNode, const char *strTag, bool value)
+{
+ SetString(pRootNode, strTag, value ? "true" : "false");
+}
+
+void XMLUtils::SetHex(TiXmlNode* pRootNode, const char *strTag, uint32_t value)
+{
+ CStdString strValue;
+ strValue.Format("%x", value);
+ SetString(pRootNode, strTag, strValue);
+}
+
+void XMLUtils::SetPath(TiXmlNode* pRootNode, const char *strTag, const CStdString& strValue)
+{
+ TiXmlElement newElement(strTag);
+ newElement.SetAttribute("pathversion", CSpecialProtocol::path_version);
+ TiXmlNode *pNewNode = pRootNode->InsertEndChild(newElement);
+ if (pNewNode)
+ {
+ TiXmlText value(strValue);
+ pNewNode->InsertEndChild(value);
+ }
+}
diff --git a/guilib/XMLUtils.h b/guilib/XMLUtils.h
new file mode 100644
index 0000000000..22a6723e99
--- /dev/null
+++ b/guilib/XMLUtils.h
@@ -0,0 +1,54 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "StdString.h"
+#include "tinyXML/tinyxml.h" // no use forwarding these, as this class is the main workhorse anyway,
+ // thus it simplifies the include patterns
+
+class XMLUtils
+{
+public:
+ static bool HasUTF8Declaration(const CStdString &strXML);
+
+ static bool GetHex(const TiXmlNode* pRootNode, const char* strTag, uint32_t& dwHexValue);
+ static bool GetUInt(const TiXmlNode* pRootNode, const char* strTag, uint32_t& dwUIntValue);
+ static bool GetLong(const TiXmlNode* pRootNode, const char* strTag, long& lLongValue);
+ static bool GetFloat(const TiXmlNode* pRootNode, const char* strTag, float& value);
+ static bool GetInt(const TiXmlNode* pRootNode, const char* strTag, int& iIntValue);
+ static bool GetBoolean(const TiXmlNode* pRootNode, const char* strTag, bool& bBoolValue);
+ static bool GetString(const TiXmlNode* pRootNode, const char* strTag, CStdString& strStringValue);
+ static bool GetAdditiveString(const TiXmlNode* pRootNode, const char* strTag, const CStdString& strSeparator, CStdString& strStringValue);
+ static bool GetEncoding(const TiXmlDocument* pDoc, CStdString& strEncoding);
+ static bool GetPath(const TiXmlNode* pRootNode, const char* strTag, CStdString& strStringValue);
+ static bool GetFloat(const TiXmlNode* pRootNode, const char* strTag, float& value, const float min, const float max);
+ static bool GetInt(const TiXmlNode* pRootNode, const char* strTag, int& iIntValue, const int min, const int max);
+
+ static void SetString(TiXmlNode* pRootNode, const char *strTag, const CStdString& strValue);
+ static void SetInt(TiXmlNode* pRootNode, const char *strTag, int value);
+ static void SetFloat(TiXmlNode* pRootNode, const char *strTag, float value);
+ static void SetBoolean(TiXmlNode* pRootNode, const char *strTag, bool value);
+ static void SetHex(TiXmlNode* pRootNode, const char *strTag, uint32_t value);
+ static void SetPath(TiXmlNode* pRootNode, const char *strTag, const CStdString& strValue);
+ static void SetLong(TiXmlNode* pRootNode, const char *strTag, long iValue);
+};
+
diff --git a/guilib/common/IRServerSuite/IRServerSuite.cpp b/guilib/common/IRServerSuite/IRServerSuite.cpp
new file mode 100644
index 0000000000..0e70b368d4
--- /dev/null
+++ b/guilib/common/IRServerSuite/IRServerSuite.cpp
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "IRServerSuite.h"
+#include "IrssMessage.h"
+#include "ButtonTranslator.h"
+#include "log.h"
+#include "AdvancedSettings.h"
+
+#define IRSS_PORT 24000
+
+CRemoteControl g_RemoteControl;
+
+CRemoteControl::CRemoteControl()
+{
+ m_socket = INVALID_SOCKET;
+ m_bInitialized = false;
+ m_isConnecting = false;
+ Reset();
+}
+
+CRemoteControl::~CRemoteControl()
+{
+ Close();
+}
+
+void CRemoteControl::Disconnect()
+{
+ StopThread();
+ Close();
+}
+
+void CRemoteControl::Close()
+{
+ m_isConnecting = false;
+ if (m_socket != INVALID_SOCKET)
+ {
+ if (m_bInitialized)
+ {
+ m_bInitialized = false;
+ CIrssMessage message(IRSSMT_UnregisterClient, IRSSMF_Request | IRSSMF_ForceNotRespond);
+ SendPacket(message);
+ }
+ shutdown(m_socket, SD_BOTH);
+ closesocket(m_socket);
+ m_socket = INVALID_SOCKET;
+ }
+}
+
+void CRemoteControl::Reset()
+{
+ m_isHolding = false;
+ m_button = 0;
+}
+
+void CRemoteControl::Initialize()
+{
+ //trying to connect when there is nothing to connect to is kinda slow so kick it off in a thread.
+ Create();
+ SetName("CRemoteControl");
+}
+
+void CRemoteControl::Process()
+{
+ int iTries = 1;
+ DWORD iMsRetryDelay = 5000;
+ DWORD time = timeGetTime() - iMsRetryDelay;
+ // try to connect 6 times @ a 5 second interval (30 seconds)
+ // multiple tries because irss service might be up and running a little later then xbmc on boot.
+ while (!m_bStop && iTries <= 6)
+ {
+ if (timeGetTime() - time >= iMsRetryDelay)
+ {
+ time = timeGetTime();
+ if (Connect())
+ break;
+ iTries++;
+ }
+ Sleep(10);
+ }
+}
+
+bool CRemoteControl::Connect()
+{
+ m_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (m_socket == INVALID_SOCKET)
+ {
+ return false; //Couldn't create the socket
+ }
+ // Get the local host information
+ hostent* localHost = gethostbyname("");
+ char* localIP = inet_ntoa (*(struct in_addr *)*localHost->h_addr_list);
+
+ SOCKADDR_IN target;
+ memset(&target, 0, sizeof(SOCKADDR_IN));
+
+ target.sin_family = AF_INET;
+ target.sin_addr.s_addr = inet_addr(localIP);
+ target.sin_port = htons (IRSS_PORT);
+
+ if (connect(m_socket, (SOCKADDR *)&target, sizeof(target)) == SOCKET_ERROR)
+ {
+ Close();
+ return false; //Couldn't connect, irss not available
+ }
+
+ u_long iMode = 1; //non-blocking
+ if (ioctlsocket(m_socket, FIONBIO, &iMode) == SOCKET_ERROR)
+ {
+ CLog::Log(LOGERROR, "IRServerSuite: failed to set socket to non-blocking.");
+ Close();
+ return false;
+ }
+
+ //register
+ CIrssMessage mess(IRSSMT_RegisterClient, IRSSMF_Request);
+ if (!SendPacket(mess))
+ {
+ CLog::Log(LOGERROR, "IRServerSuite: failed to send RegisterClient packet.");
+ return false;
+ }
+ m_isConnecting = true;
+ return true;
+}
+
+bool CRemoteControl::SendPacket(CIrssMessage& message)
+{
+ int iSize = 0;
+ char* bytes = message.ToBytes(iSize);
+ char buffer[4];
+ uint32_t len = htonl(iSize);
+ memcpy(&buffer[0], &len, 4);
+ bool bResult = WriteN(&buffer[0], 4);
+ if (bResult)
+ {
+ bResult = WriteN(bytes, iSize);
+ }
+ delete[] bytes;
+ if (!bResult)
+ {
+ Close();
+ return false;
+ }
+ return true;
+}
+
+
+void CRemoteControl::Update()
+{
+ if ((!m_bInitialized && !m_isConnecting) || (m_socket == INVALID_SOCKET))
+ {
+ return;
+ }
+
+ CIrssMessage mess;
+ if (!ReadPacket(mess))
+ {
+ return;
+ }
+ switch (mess.GetType())
+ {
+ case IRSSMT_RegisterClient:
+ m_isConnecting = false;
+ if ((mess.GetFlags() & IRSSMF_Success) != IRSSMF_Success)
+ {
+ //uh oh, it failed to register
+ Close();
+ CLog::Log(LOGERROR, "IRServerSuite: failed to register XBMC as a client.");
+ }
+ else
+ {
+ m_bInitialized = true;
+ //request info about receivers
+ CIrssMessage mess(IRSSMT_DetectedReceivers, IRSSMF_Request);
+ if (!SendPacket(mess))
+ {
+ CLog::Log(LOGERROR, "IRServerSuite: failed to send AvailableReceivers packet.");
+ }
+ mess.SetType(IRSSMT_AvailableReceivers);
+ if (!SendPacket(mess))
+ {
+ CLog::Log(LOGERROR, "IRServerSuite: failed to send AvailableReceivers packet.");
+ }
+ mess.SetType(IRSSMT_ActiveReceivers);
+ if (!SendPacket(mess))
+ {
+ CLog::Log(LOGERROR, "IRServerSuite: failed to send AvailableReceivers packet.");
+ }
+ }
+ break;
+ case IRSSMT_RemoteEvent:
+ HandleRemoteEvent(mess);
+ break;
+ case IRSSMT_Error:
+ //I suppose the errormessage is in the packet somewhere...
+ CLog::Log(LOGERROR, "IRServerSuite: we got an error message.");
+ break;
+ case IRSSMT_ServerShutdown:
+ Close();
+ break;
+ case IRSSMT_ServerSuspend:
+ //should we do something?
+ break;
+ case IRSSMT_ServerResume:
+ //should we do something?
+ break;
+ case IRSSMT_AvailableReceivers:
+ {
+ uint32_t size = mess.GetDataSize();
+ if (size > 0)
+ {
+ char* data = mess.GetData();
+ char* availablereceivers = new char[size + 1];
+ memcpy(availablereceivers, data, size);
+ availablereceivers[size] = '\0';
+ CLog::Log(LOGINFO, "IRServerSuite: Available receivers: %s", availablereceivers);
+ delete[] availablereceivers;
+ }
+ }
+ break;
+ case IRSSMT_DetectedReceivers:
+ {
+ uint32_t size = mess.GetDataSize();
+ if (size > 0)
+ {
+ char* data = mess.GetData();
+ char* detectedreceivers = new char[size + 1];
+ memcpy(detectedreceivers, data, size);
+ detectedreceivers[size] = '\0';
+ CLog::Log(LOGINFO, "IRServerSuite: Detected receivers: %s", detectedreceivers);
+ delete[] detectedreceivers;
+ }
+ }
+ break;
+ case IRSSMT_ActiveReceivers:
+ {
+ uint32_t size = mess.GetDataSize();
+ if (size > 0)
+ {
+ char* data = mess.GetData();
+ char* activereceivers = new char[size + 1];
+ memcpy(activereceivers, data, size);
+ activereceivers[size] = '\0';
+ CLog::Log(LOGINFO, "IRServerSuite: Active receivers: %s", activereceivers);
+ delete[] activereceivers;
+ }
+ }
+ break;
+ }
+}
+
+bool CRemoteControl::HandleRemoteEvent(CIrssMessage& message)
+{
+ try
+ {
+ //flag should be notify, maybe check it?
+ char* data = message.GetData();
+ uint32_t datalen = message.GetDataSize();
+ char* deviceName;
+ char* keycode;
+ uint32_t devicenamelength;
+ uint32_t keycodelength;
+ if (datalen == 0)
+ {
+ CLog::Log(LOGERROR, "IRServerSuite: no data in remote message.");
+ return false;
+ }
+ if (datalen <= 8)
+ {
+ //seems to be version 1.0.4.1, only keycode is sent, use Microsoft MCE mapping??
+ devicenamelength = 13;
+ deviceName = new char[devicenamelength + 1];
+ sprintf(deviceName, "Microsoft MCE");
+ keycodelength = datalen;
+ keycode = new char[keycodelength + 1];
+ memcpy(keycode, data, keycodelength);
+ }
+ else
+ {
+ //first 4 bytes is devicename length
+ memcpy(&devicenamelength, data, 4);
+ //devicename itself
+ if (datalen < 4 + devicenamelength)
+ {
+ CLog::Log(LOGERROR, "IRServerSuite: invalid data in remote message (size: %u).", datalen);
+ return false;
+ }
+ deviceName = new char[devicenamelength + 1];
+ memcpy(deviceName, data + 4, devicenamelength);
+ if (datalen < 8 + devicenamelength)
+ {
+ CLog::Log(LOGERROR, "IRServerSuite: invalid data in remote message (size: %u).", datalen);
+ return false;
+ }
+ //next 4 bytes is keycode length
+ memcpy(&keycodelength, data + 4 + devicenamelength, 4);
+ //keycode itself
+ if (datalen < 8 + devicenamelength + keycodelength)
+ {
+ CLog::Log(LOGERROR, "IRServerSuite: invalid data in remote message (size: %u).", datalen);
+ delete[] deviceName;
+ return false;
+ }
+ keycode = new char[keycodelength + 1];
+ memcpy(keycode, data + 8 + devicenamelength, keycodelength);
+ }
+ deviceName[devicenamelength] = '\0';
+ keycode[keycodelength] = '\0';
+ //translate to a buttoncode xbmc understands
+ m_button = CButtonTranslator::GetInstance().TranslateLircRemoteString(deviceName, keycode);
+ if (g_advancedSettings.m_logLevel == LOG_LEVEL_DEBUG_FREEMEM)
+ {
+ CLog::Log(LOGINFO, "IRServerSuite, RemoteEvent: %s %s", deviceName, keycode);
+ }
+ delete[] deviceName;
+ delete[] keycode;
+ return true;
+ }
+ catch(...)
+ {
+ CLog::Log(LOGERROR, "IRServerSuite: exception while processing RemoteEvent.");
+ return false;
+ }
+}
+
+int CRemoteControl::ReadN(char *buffer, int n)
+{
+ int nOriginalSize = n;
+ memset(buffer, 0, n);
+ char *ptr = buffer;
+ while (n > 0)
+ {
+ int nBytes = 0;
+ nBytes = recv(m_socket, ptr, n, 0);
+
+ if (WSAGetLastError() == WSAEWOULDBLOCK)
+ {
+ return nOriginalSize - n;
+ }
+ if (nBytes < 0)
+ {
+ if (!m_isConnecting)
+ {
+ CLog::Log(LOGERROR, "%s, IRServerSuite recv error %d", __FUNCTION__, GetLastError());
+ }
+ Close();
+ return -1;
+ }
+
+ if (nBytes == 0)
+ {
+ CLog::Log(LOGDEBUG,"%s, IRServerSuite socket closed by server", __FUNCTION__);
+ Close();
+ break;
+ }
+
+ n -= nBytes;
+ ptr += nBytes;
+ }
+
+ return nOriginalSize - n;
+}
+
+bool CRemoteControl::WriteN(const char *buffer, int n)
+{
+ const char *ptr = buffer;
+ while (n > 0)
+ {
+ int nBytes = send(m_socket, ptr, n, 0);
+ if (nBytes < 0)
+ {
+ CLog::Log(LOGERROR, "%s, IRServerSuite send error %d (%d bytes)", __FUNCTION__, GetLastError(), n);
+ Close();
+ return false;
+ }
+
+ if (nBytes == 0)
+ break;
+
+ n -= nBytes;
+ ptr += nBytes;
+ }
+
+ return n == 0;
+}
+
+bool CRemoteControl::ReadPacket(CIrssMessage &message)
+{
+ try
+ {
+ char sizebuf[4];
+ int iRead = ReadN(&sizebuf[0], 4);
+ if (iRead <= 0) return false; //nothing to read
+ if (iRead != 4)
+ {
+ CLog::Log(LOGERROR, "IRServerSuite: failed to read packetsize.");
+ return false;
+ }
+ uint32_t size = 0;
+ memcpy(&size, &sizebuf[0], 4);
+ size = ntohl(size);
+ char* messagebytes = new char[size];
+ if (ReadN(messagebytes, size) != size)
+ {
+ CLog::Log(LOGERROR, "IRServerSuite: failed to read packet.");
+ return false;
+ }
+ if (!CIrssMessage::FromBytes(messagebytes, size, message))
+ {
+ CLog::Log(LOGERROR, "IRServerSuite: invalid packet received (size: %u).", size);
+ return false;
+ }
+ delete[] messagebytes;
+ return true;
+ }
+ catch(...)
+ {
+ CLog::Log(LOGERROR, "IRServerSuite: exception while processing packet.");
+ return false;
+ }
+}
+
+WORD CRemoteControl::GetButton()
+{
+ return m_button;
+}
+
+bool CRemoteControl::IsHolding()
+{
+ return m_isHolding;
+}
diff --git a/guilib/common/IRServerSuite/IRServerSuite.h b/guilib/common/IRServerSuite/IRServerSuite.h
new file mode 100644
index 0000000000..d2cb322640
--- /dev/null
+++ b/guilib/common/IRServerSuite/IRServerSuite.h
@@ -0,0 +1,64 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include <winsock2.h>
+#include "StdString.h"
+#include "IrssMessage.h"
+#include "Thread.h"
+
+class CRemoteControl : CThread
+{
+public:
+ CRemoteControl();
+ ~CRemoteControl();
+ void Initialize();
+ void Disconnect();
+ void Reset();
+ void Update();
+ WORD GetButton();
+ bool IsHolding();
+ bool IsInitialized() {return m_bInitialized;}
+ bool IsInUse() {return false;}
+
+protected:
+ virtual void Process();
+
+private:
+ WORD m_button;
+ bool m_isHolding;
+ bool m_bInitialized;
+ SOCKET m_socket;
+ bool m_isConnecting;
+ CStdString m_deviceName;
+ CStdString m_keyCode;
+
+ bool SendPacket(CIrssMessage& message);
+ bool ReadPacket(CIrssMessage& message);
+ int ReadN(char *buffer, int n);
+ bool WriteN(const char *buffer, int n);
+ bool Connect();
+ void Close();
+
+ bool HandleRemoteEvent(CIrssMessage& message);
+};
+
+extern CRemoteControl g_RemoteControl;
diff --git a/guilib/common/IRServerSuite/IrssMessage.cpp b/guilib/common/IRServerSuite/IrssMessage.cpp
new file mode 100644
index 0000000000..7f8d40b174
--- /dev/null
+++ b/guilib/common/IRServerSuite/IrssMessage.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "IrssMessage.h"
+
+CIrssMessage::CIrssMessage()
+{
+ m_type = IRSSMT_Unknown;
+ m_flags = 0;
+ m_data = NULL;
+ m_dataSize = 0;
+}
+
+CIrssMessage::CIrssMessage(IRSS_MessageType type, uint32_t flags)
+{
+ m_type = type;
+ m_flags = flags;
+ m_data = NULL;
+ m_dataSize = 0;
+}
+
+CIrssMessage::CIrssMessage(IRSS_MessageType type, uint32_t flags, char* data, int size)
+{
+ m_type = type;
+ m_flags = flags;
+ SetDataAsBytes(data, size);
+}
+
+CIrssMessage::CIrssMessage(IRSS_MessageType type, uint32_t flags, const CStdString& data)
+{
+ m_type = type;
+ m_flags = flags;
+ SetDataAsString(data);
+}
+
+CIrssMessage::~CIrssMessage()
+{
+ FreeData();
+}
+
+void CIrssMessage::SetDataAsBytes(char* data, int size)
+{
+ if (!data)
+ {
+ FreeData();
+ }
+ else
+ {
+ m_data = (char*)malloc(size * sizeof(char));
+ memcpy(m_data, data, size);
+ m_dataSize = size;
+ }
+}
+
+void CIrssMessage::SetDataAsString(const CStdString& data)
+{
+ if (!data || data.IsEmpty())
+ {
+ FreeData();
+ }
+ else
+ {
+ m_data = strdup(data.c_str());
+ m_dataSize = strlen(data.c_str());
+ }
+}
+
+void CIrssMessage::FreeData()
+{
+ free(m_data);
+ m_data = NULL;
+ m_dataSize = 0;
+}
+
+char* CIrssMessage::ToBytes(int& size)
+{
+ int dataLength = 0;
+ if (m_data)
+ {
+ dataLength = m_dataSize;
+ }
+
+ size = 8 + dataLength;
+ char* byteArray = new char[size];
+
+ memcpy(&byteArray[0], &m_type, 4);
+ memcpy(&byteArray[4], &m_flags, 4);
+
+ if (m_data)
+ {
+ memcpy(&byteArray[8], &m_data, m_dataSize);
+ }
+
+ return byteArray;
+}
+
+bool CIrssMessage::FromBytes(char* from, int size, CIrssMessage& message)
+{
+ if (!from)
+ return false;
+
+ if (size < 8)
+ return false;
+
+ //IRSS_MessageType type = (MessageType)BitConverter.ToInt32(from, 0);
+ //IRSS_MessageFlags flags = (MessageFlags)BitConverter.ToInt32(from, 4);
+ uint32_t type;
+ memcpy(&type, from, 4);
+ uint32_t flags;
+ memcpy(&flags, from + 4, 4);
+
+ message.SetType((IRSS_MessageType)type);
+ message.SetFlags(flags);
+ if (size > 8)
+ {
+ message.SetDataAsBytes(from + 8, size - 8);
+ }
+ return true;
+}
+
+void CIrssMessage::SetType(IRSS_MessageType type)
+{
+ m_type = type;
+}
+void CIrssMessage::SetFlags(uint32_t flags)
+{
+ m_flags = flags;
+}
diff --git a/guilib/common/IRServerSuite/IrssMessage.h b/guilib/common/IRServerSuite/IrssMessage.h
new file mode 100644
index 0000000000..d5ddefa0a7
--- /dev/null
+++ b/guilib/common/IRServerSuite/IrssMessage.h
@@ -0,0 +1,209 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "StdString.h"
+
+ /// <summary>
+ /// Type of message.
+ /// </summary>
+ enum IRSS_MessageType
+ {
+ /// <summary>
+ /// Unknown message type.
+ /// </summary>
+ IRSSMT_Unknown = 0,
+
+ /// <summary>
+ /// Register Client.
+ /// </summary>
+ IRSSMT_RegisterClient = 1,
+ /// <summary>
+ /// Unregister Client.
+ /// </summary>
+ IRSSMT_UnregisterClient = 2,
+
+ /// <summary>
+ /// Register Repeater.
+ /// </summary>
+ IRSSMT_RegisterRepeater = 3,
+ /// <summary>
+ /// Unregister Repeater.
+ /// </summary>
+ IRSSMT_UnregisterRepeater = 4,
+
+ /// <summary>
+ /// Learn IR Command.
+ /// </summary>
+ IRSSMT_LearnIR = 5,
+ /// <summary>
+ /// Blast IR Command.
+ /// </summary>
+ IRSSMT_BlastIR = 6,
+
+ /// <summary>
+ /// Error.
+ /// </summary>
+ IRSSMT_Error = 7,
+
+ /// <summary>
+ /// Server Shutdown.
+ /// </summary>
+ IRSSMT_ServerShutdown = 8,
+ /// <summary>
+ /// Server Suspend.
+ /// </summary>
+ IRSSMT_ServerSuspend = 9,
+ /// <summary>
+ /// Server Resume
+ /// </summary>
+ IRSSMT_ServerResume = 10,
+
+ /// <summary>
+ /// Remote Event.
+ /// </summary>
+ IRSSMT_RemoteEvent = 11,
+ /// <summary>
+ /// Keyboard Event.
+ /// </summary>
+ IRSSMT_KeyboardEvent = 12,
+ /// <summary>
+ /// Mouse Event.
+ /// </summary>
+ IRSSMT_MouseEvent = 13,
+
+ /// <summary>
+ /// Forward a Remote Event.
+ /// </summary>
+ IRSSMT_ForwardRemoteEvent = 14,
+ /// <summary>
+ /// Forward a Keyboard Event.
+ /// </summary>
+ IRSSMT_ForwardKeyboardEvent = 15,
+ /// <summary>
+ /// Forward a Mouse Event.
+ /// </summary>
+ IRSSMT_ForwardMouseEvent = 16,
+
+ /// <summary>
+ /// Available Receivers.
+ /// </summary>
+ IRSSMT_AvailableReceivers = 17,
+ /// <summary>
+ /// Available Blasters.
+ /// </summary>
+ IRSSMT_AvailableBlasters = 18,
+ /// <summary>
+ /// Active Receivers.
+ /// </summary>
+ IRSSMT_ActiveReceivers = 19,
+ /// <summary>
+ /// Active Blasters.
+ /// </summary>
+ IRSSMT_ActiveBlasters = 20,
+ /// <summary>
+ /// Detected Receivers.
+ /// </summary>
+ IRSSMT_DetectedReceivers = 21,
+ /// <summary>
+ /// Detected Blasters.
+ /// </summary>
+ IRSSMT_DetectedBlasters = 22,
+ };
+
+ /// <summary>
+ /// Flags to determine more information about the message.
+ /// </summary>
+ enum IRSS_MessageFlags
+ {
+ /// <summary>
+ /// No Flags.
+ /// </summary>
+ IRSSMF_None = 0x0000,
+
+ /// <summary>
+ /// Message is a Request.
+ /// </summary>
+ IRSSMF_Request = 0x0001,
+ /// <summary>
+ /// Message is a Response to a received Message.
+ /// </summary>
+ IRSSMF_Response = 0x0002,
+ /// <summary>
+ /// Message is a Notification.
+ /// </summary>
+ IRSSMF_Notify = 0x0004,
+
+ /// <summary>
+ /// Operation Success.
+ /// </summary>
+ IRSSMF_Success = 0x0008,
+ /// <summary>
+ /// Operation Failure.
+ /// </summary>
+ IRSSMF_Failure = 0x0010,
+ /// <summary>
+ /// Operation Time-Out.
+ /// </summary>
+ IRSSMF_Timeout = 0x0020,
+
+ //IRSSMF_Error = 0x0040,
+
+ //IRSSMF_DataString = 0x0080,
+ //IRSSMF_DataBytes = 0x0100,
+
+ //IRSSMF_ForceRespond = 0x0200,
+
+ /// <summary>
+ /// Force the recipient not to respond.
+ /// </summary>
+ IRSSMF_ForceNotRespond = 0x0400,
+ };
+
+class CIrssMessage
+{
+public:
+ CIrssMessage();
+ CIrssMessage(IRSS_MessageType type, uint32_t flags);
+ CIrssMessage(IRSS_MessageType type, uint32_t flags, char* data, int size);
+ CIrssMessage(IRSS_MessageType type, uint32_t flags, const CStdString& data);
+ ~CIrssMessage();
+
+ void SetDataAsBytes(char* data, int size);
+ void SetDataAsString(const CStdString& data);
+ char* ToBytes(int& size);
+ void SetType(IRSS_MessageType type);
+ void SetFlags(uint32_t flags);
+ IRSS_MessageType GetType() {return m_type;}
+ uint32_t GetFlags() {return m_flags;}
+ char* GetData() {return m_data;}
+ uint32_t GetDataSize() {return m_dataSize;}
+ static bool FromBytes(char* from, int size, CIrssMessage& message);
+
+private:
+ IRSS_MessageType m_type;
+ uint32_t m_flags;
+
+ char* m_data;
+ int m_dataSize;
+
+ void FreeData();
+};
diff --git a/guilib/common/LIRC.cpp b/guilib/common/LIRC.cpp
new file mode 100644
index 0000000000..9b7bf2dcd2
--- /dev/null
+++ b/guilib/common/LIRC.cpp
@@ -0,0 +1,257 @@
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/inotify.h>
+#include <limits.h>
+#include <unistd.h>
+#include "LIRC.h"
+#include "ButtonTranslator.h"
+#include "log.h"
+#include "AdvancedSettings.h"
+#include "FileSystem/File.h"
+
+#define LIRC_DEVICE "/dev/lircd"
+
+CRemoteControl g_RemoteControl;
+
+CRemoteControl::CRemoteControl()
+{
+ m_fd = -1;
+ m_file = NULL;
+ m_bInitialized = false;
+ m_skipHold = false;
+ m_button = 0;
+ m_isHolding = false;
+ m_used = true;
+ m_deviceName = LIRC_DEVICE;
+ m_inotify_fd = -1;
+ m_inotify_wd = -1;
+ m_bLogConnectFailure = true;
+ m_lastInitAttempt = -5000;
+ m_initRetryPeriod = 5000;
+ Reset();
+}
+
+CRemoteControl::~CRemoteControl()
+{
+ if (m_file != NULL)
+ fclose(m_file);
+}
+
+void CRemoteControl::setUsed(bool value)
+{
+ m_used=value;
+ if (!value)
+ CLog::Log(LOGINFO, "LIRC %s: disabled", __FUNCTION__);
+}
+
+void CRemoteControl::Reset()
+{
+ m_isHolding = false;
+ m_button = 0;
+}
+
+void CRemoteControl::Disconnect()
+{
+ if (!m_used)
+ return;
+
+ if (m_fd != -1)
+ {
+ m_bInitialized = false;
+ if (m_file != NULL)
+ fclose(m_file);
+ m_fd = -1;
+ m_file = NULL;
+ if (m_inotify_wd >= 0) {
+ inotify_rm_watch(m_inotify_fd, m_inotify_wd);
+ m_inotify_wd = -1;
+ }
+ if (m_inotify_fd >= 0)
+ close(m_inotify_fd);
+ }
+}
+
+void CRemoteControl::setDeviceName(const CStdString& value)
+{
+ if (value.length()>0)
+ m_deviceName=value;
+ else
+ m_deviceName=LIRC_DEVICE;
+}
+
+void CRemoteControl::Initialize()
+{
+ struct sockaddr_un addr;
+ int now = timeGetTime();
+
+ if (!m_used || now < m_lastInitAttempt + m_initRetryPeriod)
+ return;
+ m_lastInitAttempt = now;
+
+ if (!XFILE::CFile::Exists(m_deviceName)) {
+ m_initRetryPeriod *= 2;
+ if (m_initRetryPeriod > 60000)
+ {
+ m_used = false;
+ CLog::Log(LOGDEBUG, "LIRC device %s does not exist. Giving up.", m_deviceName.c_str());
+ }
+ else
+ CLog::Log(LOGDEBUG, "LIRC device %s does not exist. Retry in %ds.", m_deviceName.c_str(), m_initRetryPeriod/1000);
+ return;
+ }
+
+ m_initRetryPeriod = 5000;
+
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, m_deviceName.c_str());
+
+ // Open the socket from which we will receive the remote commands
+ if ((m_fd = socket(AF_UNIX, SOCK_STREAM, 0)) != -1)
+ {
+ // Connect to the socket
+ if (connect(m_fd, (struct sockaddr *)&addr, sizeof(addr)) != -1)
+ {
+ int opts;
+ m_bLogConnectFailure = true;
+ if ((opts = fcntl(m_fd,F_GETFL)) != -1)
+ {
+ // Set the socket to non-blocking
+ opts = (opts | O_NONBLOCK);
+ if (fcntl(m_fd,F_SETFL,opts) != -1)
+ {
+ if ((m_file = fdopen(m_fd, "r")) != NULL)
+ {
+ // Setup inotify so we can disconnect if lircd is restarted
+ if ((m_inotify_fd = inotify_init()) >= 0)
+ {
+ // Set the fd non-blocking
+ if ((opts = fcntl(m_inotify_fd, F_GETFL)) != -1)
+ {
+ opts |= O_NONBLOCK;
+ if (fcntl(m_inotify_fd, F_SETFL, opts) != -1)
+ {
+ // Set an inotify watch on the lirc device
+ if ((m_inotify_wd = inotify_add_watch(m_inotify_fd, m_deviceName.c_str(), IN_DELETE_SELF)) != -1)
+ {
+ m_bInitialized = true;
+ CLog::Log(LOGINFO, "LIRC %s: sucessfully started on: %s", __FUNCTION__, addr.sun_path);
+ }
+ else
+ CLog::Log(LOGDEBUG, "LIRC: Failed to initialize Inotify. LIRC device will not be monitored.");
+ }
+ }
+ }
+ }
+ else
+ CLog::Log(LOGERROR, "LIRC %s: fdopen failed: %s", __FUNCTION__, strerror(errno));
+ }
+ else
+ CLog::Log(LOGERROR, "LIRC %s: fcntl(F_SETFL) failed: %s", __FUNCTION__, strerror(errno));
+ }
+ else
+ CLog::Log(LOGERROR, "LIRC %s: fcntl(F_GETFL) failed: %s", __FUNCTION__, strerror(errno));
+ }
+ else
+ {
+ if (m_bLogConnectFailure)
+ {
+ CLog::Log(LOGINFO, "LIRC %s: connect failed: %s", __FUNCTION__, strerror(errno));
+ m_bLogConnectFailure = false;
+ }
+ }
+ }
+ else
+ CLog::Log(LOGINFO, "LIRC %s: socket failed: %s", __FUNCTION__, strerror(errno));
+ if (!m_bInitialized)
+ Disconnect();
+}
+
+bool CRemoteControl::CheckDevice() {
+ if (m_inotify_fd < 0 || m_inotify_wd < 0)
+ return true; // inotify wasn't setup for some reason, assume all is well
+ int bufsize = sizeof(struct inotify_event) + PATH_MAX;
+ char buf[bufsize];
+ int ret = read(m_inotify_fd, buf, bufsize);
+ for (int i = 0; i + (int)sizeof(struct inotify_event) <= ret;) {
+ struct inotify_event* e = (struct inotify_event*)(buf+i);
+ if (e->mask & IN_DELETE_SELF) {
+ CLog::Log(LOGDEBUG, "LIRC device removed, disconnecting...");
+ Disconnect();
+ return false;
+ }
+ i += sizeof(struct inotify_event)+e->len;
+ }
+ return true;
+}
+
+void CRemoteControl::Update()
+{
+ if (!m_bInitialized || !m_used )
+ return;
+
+ if (!CheckDevice())
+ return;
+
+ Uint32 now = SDL_GetTicks();
+
+ // Read a line from the socket
+ while (fgets(m_buf, sizeof(m_buf), m_file) != NULL)
+ {
+ // Remove the \n
+ m_buf[strlen(m_buf)-1] = '\0';
+
+ // Parse the result. Sample line:
+ // 000000037ff07bdd 00 OK mceusb
+ char scanCode[128];
+ char buttonName[128];
+ char repeatStr[4];
+ char deviceName[128];
+ sscanf(m_buf, "%s %s %s %s", &scanCode[0], &repeatStr[0], &buttonName[0], &deviceName[0]);
+
+ // Some template LIRC configuration have button names in apostrophes or quotes.
+ // If we got a quoted button name, strip 'em
+ unsigned int buttonNameLen = strlen(buttonName);
+ if ( buttonNameLen > 2
+ && ( (buttonName[0] == '\'' && buttonName[buttonNameLen-1] == '\'')
+ || ((buttonName[0] == '"' && buttonName[buttonNameLen-1] == '"') ) ) )
+ {
+ memmove( buttonName, buttonName + 1, buttonNameLen - 2 );
+ buttonName[ buttonNameLen - 2 ] = '\0';
+ }
+
+ m_button = CButtonTranslator::GetInstance().TranslateLircRemoteString(deviceName, buttonName);
+
+ if (strcmp(repeatStr, "00") == 0)
+ {
+ CLog::Log(LOGDEBUG, "LIRC: %s - NEW at %d:%s (%s)", __FUNCTION__, now, m_buf, buttonName);
+ m_firstClickTime = now;
+ m_isHolding = false;
+ m_skipHold = true;
+ return;
+ }
+ else if (now - m_firstClickTime >= (Uint32) g_advancedSettings.m_remoteRepeat && !m_skipHold)
+ {
+ m_isHolding = true;
+ }
+ else
+ {
+ m_isHolding = false;
+ m_button = 0;
+ }
+ }
+ if (feof(m_file) != 0)
+ Disconnect();
+ m_skipHold = false;
+}
+
+WORD CRemoteControl::GetButton()
+{
+ return m_button;
+}
+
+bool CRemoteControl::IsHolding()
+{
+ return m_isHolding;
+}
diff --git a/guilib/common/LIRC.h b/guilib/common/LIRC.h
new file mode 100644
index 0000000000..fc6882ab6d
--- /dev/null
+++ b/guilib/common/LIRC.h
@@ -0,0 +1,44 @@
+#ifndef LIRC_H
+#define LIRC_H
+
+#include "../system.h"
+#include "StdString.h"
+
+class CRemoteControl
+{
+public:
+ CRemoteControl();
+ ~CRemoteControl();
+ void Initialize();
+ void Disconnect();
+ void Reset();
+ void Update();
+ WORD GetButton();
+ bool IsHolding();
+ void setDeviceName(const CStdString& value);
+ void setUsed(bool value);
+ bool IsInUse() const { return m_used; }
+ bool IsInitialized() const { return m_bInitialized; }
+
+private:
+ int m_fd;
+ int m_inotify_fd;
+ int m_inotify_wd;
+ int m_lastInitAttempt;
+ int m_initRetryPeriod;
+ FILE* m_file;
+ bool m_isHolding;
+ WORD m_button;
+ char m_buf[128];
+ bool m_bInitialized;
+ bool m_skipHold;
+ bool m_used;
+ bool m_bLogConnectFailure;
+ Uint32 m_firstClickTime;
+ CStdString m_deviceName;
+ bool CheckDevice();
+};
+
+extern CRemoteControl g_RemoteControl;
+
+#endif
diff --git a/guilib/common/Makefile.in b/guilib/common/Makefile.in
new file mode 100644
index 0000000000..757c468768
--- /dev/null
+++ b/guilib/common/Makefile.in
@@ -0,0 +1,14 @@
+ARCH=@ARCH@
+
+INCLUDES=-I. -I../ -I../../xbmc -I../../xbmc/linux -I../../xbmc/utils
+
+ifeq ($(findstring osx,$(ARCH)), osx)
+SRCS=SDLJoystick.cpp
+else
+SRCS=SDLJoystick.cpp LIRC.cpp
+endif
+
+LIB=gui_common.a
+
+include ../../Makefile.include
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
diff --git a/guilib/common/SDLJoystick.cpp b/guilib/common/SDLJoystick.cpp
new file mode 100644
index 0000000000..9ec94f5040
--- /dev/null
+++ b/guilib/common/SDLJoystick.cpp
@@ -0,0 +1,388 @@
+#include "system.h"
+#include "../Key.h"
+#include "SDLJoystick.h"
+#include "ButtonTranslator.h"
+#include "utils/log.h"
+
+#include <math.h>
+
+#ifdef HAS_SDL_JOYSTICK
+
+using namespace std;
+
+CJoystick g_Joystick; // global
+
+CJoystick::CJoystick()
+{
+ Reset();
+ m_NumAxes = 0;
+ m_AxisId = 0;
+ m_JoyId = 0;
+ m_ButtonId = 0;
+ m_HatId = 0;
+ m_HatState = SDL_HAT_CENTERED;
+ m_ActiveFlags = JACTIVE_NONE;
+ for (int i = 0 ; i<MAX_AXES ; i++)
+ m_Amount[i] = 0;
+
+ SetSafeRange(2000);
+}
+
+void CJoystick::Initialize(HWND hWnd)
+{
+ // clear old joystick names
+ m_JoystickNames.clear();
+
+ // any open ones? if so, close them.
+ if (m_Joysticks.size()>0)
+ {
+ for(size_t idJoy = 0; idJoy < m_Joysticks.size(); idJoy++)
+ {
+ // any joysticks unplugged?
+ if(SDL_JoystickOpened(idJoy))
+ SDL_JoystickClose(m_Joysticks[idJoy]);
+ }
+ m_Joysticks.clear();
+ m_JoyId = -1;
+ }
+
+ // any joysticks connected?
+ if (SDL_NumJoysticks()>0)
+ {
+ // load joystick names and open all connected joysticks
+ for (int i = 0 ; i<SDL_NumJoysticks() ; i++)
+ {
+ SDL_Joystick *joy = SDL_JoystickOpen(i);
+
+#ifdef __APPLE__
+ // On OS X, the 360 controllers are handled externally, since the SDL code is
+ // really buggy and doesn't handle disconnects.
+ //
+ if (std::string(SDL_JoystickName(i)).find("360") != std::string::npos)
+ {
+ CLog::Log(LOGNOTICE, "Ignoring joystick: %s", SDL_JoystickName(i));
+ continue;
+ }
+#endif
+
+ m_Joysticks.push_back(joy);
+ if (joy)
+ {
+ CalibrateAxis(joy);
+ m_JoystickNames.push_back(string(SDL_JoystickName(i)));
+ CLog::Log(LOGNOTICE, "Enabled Joystick: %s", SDL_JoystickName(i));
+ }
+ else
+ {
+ m_JoystickNames.push_back(string(""));
+ }
+ }
+ }
+
+ // disable joystick events, since we'll be polling them
+ SDL_JoystickEventState(SDL_DISABLE);
+}
+
+void CJoystick::CalibrateAxis(SDL_Joystick* joy)
+{
+ SDL_JoystickUpdate();
+
+ int numax = SDL_JoystickNumAxes(joy);
+ numax = (numax>MAX_AXES)?MAX_AXES:numax;
+
+ // get default axis states
+ for (int a = 0 ; a<numax ; a++)
+ {
+ m_DefaultAmount[a+1] = SDL_JoystickGetAxis(joy, a);
+ CLog::Log(LOGDEBUG, "Calibrated Axis: %d , default amount %d\n", a, m_DefaultAmount[a+1]);
+ }
+}
+
+void CJoystick::Reset(bool axis)
+{
+ if (axis)
+ {
+ SetAxisActive(false);
+ for (int i = 0 ; i<MAX_AXES ; i++)
+ {
+ ResetAxis(i);
+ }
+ }
+}
+
+void CJoystick::Update()
+{
+ int buttonId = -1;
+ int axisId = -1;
+ int hatId = -1;
+ int numj = m_Joysticks.size();
+ if (numj <= 0)
+ return;
+
+ // update the state of all opened joysticks
+ SDL_JoystickUpdate();
+
+ // go through all joysticks
+ for (int j = 0; j<numj; j++)
+ {
+ SDL_Joystick *joy = m_Joysticks[j];
+ int numb = SDL_JoystickNumButtons(joy);
+ int numhat = SDL_JoystickNumHats(joy);
+ int numax = SDL_JoystickNumAxes(joy);
+ numax = (numax>MAX_AXES)?MAX_AXES:numax;
+ int axisval;
+ Uint8 hatval;
+
+ // get button states first, they take priority over axis
+ for (int b = 0 ; b<numb ; b++)
+ {
+ if (SDL_JoystickGetButton(joy, b))
+ {
+ m_JoyId = j;
+ buttonId = b+1;
+ j = numj-1;
+ break;
+ }
+ }
+
+ for (int h = 0; h < numhat; h++)
+ {
+ hatval = SDL_JoystickGetHat(joy, h);
+ if (hatval != SDL_HAT_CENTERED)
+ {
+ m_JoyId = j;
+ hatId = h + 1;
+ m_HatState = hatval;
+ j = numj-1;
+ break;
+ }
+ }
+
+ // get axis states
+ m_NumAxes = numax;
+ for (int a = 0 ; a<numax ; a++)
+ {
+ axisval = SDL_JoystickGetAxis(joy, a);
+ axisId = a+1;
+ if (axisId<=0 || axisId>=MAX_AXES)
+ {
+ CLog::Log(LOGERROR, "Axis Id out of range. Maximum supported axis: %d", MAX_AXES);
+ }
+ else
+ {
+ m_Amount[axisId] = axisval; //[-32768 to 32767]
+ if (axisval!=m_DefaultAmount[axisId])
+ {
+ m_JoyId = j;
+ }
+ }
+ }
+ m_AxisId = GetAxisWithMaxAmount();
+ }
+
+ if(hatId==-1)
+ {
+ if(m_HatId!=0)
+ CLog::Log(LOGDEBUG, "Joystick %d hat %u Centered", m_JoyId, hatId);
+ m_pressTicksHat = 0;
+ SetHatActive(false);
+ m_HatId = 0;
+ }
+ else
+ {
+ if(hatId!=m_HatId)
+ {
+ CLog::Log(LOGDEBUG, "Joystick %d hat %u Down", m_JoyId, hatId);
+ m_HatId = hatId;
+ m_pressTicksHat = SDL_GetTicks();
+ }
+ SetHatActive();
+ }
+
+ if (buttonId==-1)
+ {
+ if (m_ButtonId!=0)
+ {
+ CLog::Log(LOGDEBUG, "Joystick %d button %d Up", m_JoyId, m_ButtonId);
+ }
+ m_pressTicksButton = 0;
+ SetButtonActive(false);
+ m_ButtonId = 0;
+ }
+ else
+ {
+ if (buttonId!=m_ButtonId)
+ {
+ CLog::Log(LOGDEBUG, "Joystick %d button %d Down", m_JoyId, buttonId);
+ m_ButtonId = buttonId;
+ m_pressTicksButton = SDL_GetTicks();
+ }
+ SetButtonActive();
+ }
+
+}
+
+void CJoystick::Update(SDL_Event& joyEvent)
+{
+ int buttonId = -1;
+ int axisId = -1;
+ int joyId = -1;
+ bool ignore = false; // not used for now
+ bool axis = false;
+
+ printf("JoystickEvent %i\n", joyEvent.type);
+
+ switch(joyEvent.type)
+ {
+ case SDL_JOYBUTTONDOWN:
+ m_JoyId = joyId = joyEvent.jbutton.which;
+ m_ButtonId = buttonId = joyEvent.jbutton.button + 1;
+ m_pressTicksButton = SDL_GetTicks();
+ SetButtonActive();
+ CLog::Log(LOGDEBUG, "Joystick %d button %d Down", joyId, buttonId);
+ break;
+
+ case SDL_JOYAXISMOTION:
+ joyId = joyEvent.jaxis.which;
+ axisId = joyEvent.jaxis.axis + 1;
+ m_NumAxes = SDL_JoystickNumAxes(m_Joysticks[joyId]);
+ if (axisId<=0 || axisId>=MAX_AXES)
+ {
+ CLog::Log(LOGERROR, "Axis Id out of range. Maximum supported axis: %d", MAX_AXES);
+ ignore = true;
+ break;
+ }
+ axis = true;
+ m_JoyId = joyId;
+ if (joyEvent.jaxis.value==0)
+ {
+ ignore = true;
+ m_Amount[axisId] = 0;
+ }
+ else
+ {
+ m_Amount[axisId] = joyEvent.jaxis.value; //[-32768 to 32767]
+ }
+ m_AxisId = GetAxisWithMaxAmount();
+ CLog::Log(LOGDEBUG, "Joystick %d Axis %d Amount %d", joyId, axisId, m_Amount[axisId]);
+ break;
+
+ case SDL_JOYHATMOTION:
+ m_JoyId = joyId = joyEvent.jbutton.which;
+ m_HatId = joyEvent.jhat.hat + 1;
+ m_pressTicksHat = SDL_GetTicks();
+ m_HatState = joyEvent.jhat.value;
+ SetHatActive(m_HatState != SDL_HAT_CENTERED);
+ CLog::Log(LOGDEBUG, "Joystick %d Hat %d Down with position %d", joyId, buttonId, m_HatState);
+ break;
+
+ case SDL_JOYBALLMOTION:
+ ignore = true;
+ break;
+
+ case SDL_JOYBUTTONUP:
+ m_pressTicksButton = 0;
+ SetButtonActive(false);
+ CLog::Log(LOGDEBUG, "Joystick %d button %d Up", joyEvent.jbutton.which, m_ButtonId);
+
+ default:
+ ignore = true;
+ break;
+ }
+}
+
+bool CJoystick::GetHat(int &id, int &position,bool consider_repeat)
+{
+ if (!IsHatActive())
+ return false;
+ position = m_HatState;
+ id = m_HatId;
+ if (!consider_repeat)
+ return true;
+
+ static Uint32 lastPressTicks = 0;
+ static Uint32 lastTicks = 0;
+ static Uint32 nowTicks = 0;
+
+ if ((m_HatId>=0) && m_pressTicksHat)
+ {
+ // return the id if it's the first press
+ if (lastPressTicks!=m_pressTicksHat)
+ {
+ lastPressTicks = m_pressTicksHat;
+ return true;
+ }
+ nowTicks = SDL_GetTicks();
+ if ((nowTicks-m_pressTicksHat)<500) // 500ms delay before we repeat
+ return false;
+ if ((nowTicks-lastTicks)<100) // 100ms delay before successive repeats
+ return false;
+
+ lastTicks = nowTicks;
+ }
+
+ return true;
+}
+
+bool CJoystick::GetButton(int &id, bool consider_repeat)
+{
+ if (!IsButtonActive())
+ return false;
+ if (!consider_repeat)
+ {
+ id = m_ButtonId;
+ return true;
+ }
+
+ static Uint32 lastPressTicks = 0;
+ static Uint32 lastTicks = 0;
+ static Uint32 nowTicks = 0;
+
+ if ((m_ButtonId>=0) && m_pressTicksButton)
+ {
+ // return the id if it's the first press
+ if (lastPressTicks!=m_pressTicksButton)
+ {
+ lastPressTicks = m_pressTicksButton;
+ id = m_ButtonId;
+ return true;
+ }
+ nowTicks = SDL_GetTicks();
+ if ((nowTicks-m_pressTicksButton)<500) // 500ms delay before we repeat
+ {
+ return false;
+ }
+ if ((nowTicks-lastTicks)<100) // 100ms delay before successive repeats
+ {
+ return false;
+ }
+ lastTicks = nowTicks;
+ }
+ id = m_ButtonId;
+ return true;
+}
+
+int CJoystick::GetAxisWithMaxAmount()
+{
+ static int maxAmount;
+ static int axis;
+ axis = 0;
+ maxAmount = m_SafeRange;
+ int tempf;
+ for (int i = 1 ; i<=m_NumAxes ; i++)
+ {
+ tempf = abs(m_DefaultAmount[i] - m_Amount[i]);
+ if (tempf>maxAmount)
+ {
+ maxAmount = tempf;
+ axis = i;
+ }
+ }
+ if (maxAmount==0)
+ SetAxisActive(false);
+ else
+ SetAxisActive();
+ return axis;
+}
+
+#endif
diff --git a/guilib/common/SDLJoystick.h b/guilib/common/SDLJoystick.h
new file mode 100644
index 0000000000..1aa89fecd4
--- /dev/null
+++ b/guilib/common/SDLJoystick.h
@@ -0,0 +1,78 @@
+#ifndef SDL_JOYSTICK_H
+#define SDL_JOYSTICK_H
+
+#include "../system.h"
+#include <vector>
+#include <string>
+
+#ifdef HAS_SDL_JOYSTICK
+
+#include <SDL/SDL_joystick.h>
+#include <SDL/SDL_events.h>
+
+#define MAX_AXES 64
+
+#define JACTIVE_BUTTON 0x00000001
+#define JACTIVE_AXIS 0x00000002
+#define JACTIVE_HAT 0x00000004
+#define JACTIVE_NONE 0x00000000
+
+// Class to manage all connected joysticks
+
+class CJoystick
+{
+public:
+ CJoystick();
+
+ void Initialize(HWND hwnd);
+ void Reset(bool axis=false);
+ void CalibrateAxis(SDL_Joystick *joy);
+ void ResetAxis(int axisId) { m_Amount[axisId] = 0; }
+ void Update();
+ void Update(SDL_Event& event);
+ float GetAmount(int axis)
+ {
+ if (m_Amount[axis]>0)
+ return (float)(m_Amount[axis]-m_SafeRange)/(32768.0f-(float)m_SafeRange);
+ return (float)(m_Amount[axis]+m_SafeRange)/(32768.0f-(float)m_SafeRange);
+ }
+ float GetAmount()
+ {
+ return GetAmount(m_AxisId);
+ }
+ bool GetButton (int& id, bool consider_repeat=true);
+ bool GetAxis (int &id) { if (!IsAxisActive()) return false; id=m_AxisId; return true; }
+ bool GetHat (int &id, int &position, bool consider_repeat=true);
+ std::string GetJoystick() { return (m_JoyId>-1)?m_JoystickNames[m_JoyId]:""; }
+ int GetAxisWithMaxAmount();
+ void SetSafeRange(int val) { m_SafeRange=(val>32767)?32767:val; }
+
+private:
+ void SetAxisActive(bool active=true) { m_ActiveFlags = active?(m_ActiveFlags|JACTIVE_AXIS):(m_ActiveFlags&(~JACTIVE_AXIS)); }
+ void SetButtonActive(bool active=true) { m_ActiveFlags = active?(m_ActiveFlags|JACTIVE_BUTTON):(m_ActiveFlags&(~JACTIVE_BUTTON)); }
+ void SetHatActive(bool active=true) { m_ActiveFlags = active?(m_ActiveFlags|JACTIVE_HAT):(m_ActiveFlags&(~JACTIVE_HAT)); }
+ bool IsButtonActive() { return (m_ActiveFlags & JACTIVE_BUTTON) == JACTIVE_BUTTON; }
+ bool IsAxisActive() { return (m_ActiveFlags & JACTIVE_AXIS) == JACTIVE_AXIS; }
+ bool IsHatActive() { return (m_ActiveFlags & JACTIVE_HAT) == JACTIVE_HAT; }
+
+ int m_Amount[MAX_AXES];
+ int m_DefaultAmount[MAX_AXES];
+ int m_AxisId;
+ int m_ButtonId;
+ Uint8 m_HatState;
+ int m_HatId;
+ int m_JoyId;
+ int m_NumAxes;
+ int m_SafeRange; // dead zone
+ Uint32 m_pressTicksButton;
+ Uint32 m_pressTicksHat;
+ Uint8 m_ActiveFlags;
+ std::vector<SDL_Joystick*> m_Joysticks;
+ std::vector<std::string> m_JoystickNames;
+};
+
+extern CJoystick g_Joystick;
+
+#endif
+
+#endif
diff --git a/guilib/freetype2/freetype239ST.lib b/guilib/freetype2/freetype239ST.lib
new file mode 100644
index 0000000000..235a608780
--- /dev/null
+++ b/guilib/freetype2/freetype239ST.lib
Binary files differ
diff --git a/guilib/freetype2/freetype239ST_D.lib b/guilib/freetype2/freetype239ST_D.lib
new file mode 100644
index 0000000000..0c198a8432
--- /dev/null
+++ b/guilib/freetype2/freetype239ST_D.lib
Binary files differ
diff --git a/guilib/freetype2/include/freetype/config/ftconfig.h b/guilib/freetype2/include/freetype/config/ftconfig.h
new file mode 100644
index 0000000000..3c0b8b1641
--- /dev/null
+++ b/guilib/freetype2/include/freetype/config/ftconfig.h
@@ -0,0 +1,500 @@
+/***************************************************************************/
+/* */
+/* ftconfig.h */
+/* */
+/* ANSI-specific configuration file (specification only). */
+/* */
+/* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2007, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This header file contains a number of macro definitions that are used */
+ /* by the rest of the engine. Most of the macros here are automatically */
+ /* determined at compile time, and you should not need to change it to */
+ /* port FreeType, except to compile the library with a non-ANSI */
+ /* compiler. */
+ /* */
+ /* Note however that if some specific modifications are needed, we */
+ /* advise you to place a modified copy in your build directory. */
+ /* */
+ /* The build directory is usually `freetype/builds/<system>', and */
+ /* contains system-specific files that are always included first when */
+ /* building the library. */
+ /* */
+ /* This ANSI version should stay in `include/freetype/config'. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTCONFIG_H__
+#define __FTCONFIG_H__
+
+#include <ft2build.h>
+#include FT_CONFIG_OPTIONS_H
+#include FT_CONFIG_STANDARD_LIBRARY_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* PLATFORM-SPECIFIC CONFIGURATION MACROS */
+ /* */
+ /* These macros can be toggled to suit a specific system. The current */
+ /* ones are defaults used to compile FreeType in an ANSI C environment */
+ /* (16bit compilers are also supported). Copy this file to your own */
+ /* `freetype/builds/<system>' directory, and edit it to port the engine. */
+ /* */
+ /*************************************************************************/
+
+
+ /* There are systems (like the Texas Instruments 'C54x) where a `char' */
+ /* has 16 bits. ANSI C says that sizeof(char) is always 1. Since an */
+ /* `int' has 16 bits also for this system, sizeof(int) gives 1 which */
+ /* is probably unexpected. */
+ /* */
+ /* `CHAR_BIT' (defined in limits.h) gives the number of bits in a */
+ /* `char' type. */
+
+#ifndef FT_CHAR_BIT
+#define FT_CHAR_BIT CHAR_BIT
+#endif
+
+
+ /* The size of an `int' type. */
+#if FT_UINT_MAX == 0xFFFFUL
+#define FT_SIZEOF_INT (16 / FT_CHAR_BIT)
+#elif FT_UINT_MAX == 0xFFFFFFFFUL
+#define FT_SIZEOF_INT (32 / FT_CHAR_BIT)
+#elif FT_UINT_MAX > 0xFFFFFFFFUL && FT_UINT_MAX == 0xFFFFFFFFFFFFFFFFUL
+#define FT_SIZEOF_INT (64 / FT_CHAR_BIT)
+#else
+#error "Unsupported size of `int' type!"
+#endif
+
+ /* The size of a `long' type. A five-byte `long' (as used e.g. on the */
+ /* DM642) is recognized but avoided. */
+#if FT_ULONG_MAX == 0xFFFFFFFFUL
+#define FT_SIZEOF_LONG (32 / FT_CHAR_BIT)
+#elif FT_ULONG_MAX > 0xFFFFFFFFUL && FT_ULONG_MAX == 0xFFFFFFFFFFUL
+#define FT_SIZEOF_LONG (32 / FT_CHAR_BIT)
+#elif FT_ULONG_MAX > 0xFFFFFFFFUL && FT_ULONG_MAX == 0xFFFFFFFFFFFFFFFFUL
+#define FT_SIZEOF_LONG (64 / FT_CHAR_BIT)
+#else
+#error "Unsupported size of `long' type!"
+#endif
+
+
+ /* Preferred alignment of data */
+#define FT_ALIGNMENT 8
+
+
+ /* FT_UNUSED is a macro used to indicate that a given parameter is not */
+ /* used -- this is only used to get rid of unpleasant compiler warnings */
+#ifndef FT_UNUSED
+#define FT_UNUSED( arg ) ( (arg) = (arg) )
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* AUTOMATIC CONFIGURATION MACROS */
+ /* */
+ /* These macros are computed from the ones defined above. Don't touch */
+ /* their definition, unless you know precisely what you are doing. No */
+ /* porter should need to mess with them. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Mac support */
+ /* */
+ /* This is the only necessary change, so it is defined here instead */
+ /* providing a new configuration file. */
+ /* */
+#if ( defined( __APPLE__ ) && !defined( DARWIN_NO_CARBON ) ) || \
+ ( defined( __MWERKS__ ) && defined( macintosh ) )
+ /* no Carbon frameworks for 64bit 10.4.x */
+#include "AvailabilityMacros.h"
+#if defined( __LP64__ ) && \
+ ( MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 )
+#define DARWIN_NO_CARBON 1
+#else
+#define FT_MACINTOSH 1
+#endif
+
+#elif defined( __SC__ ) || defined( __MRC__ )
+ /* Classic MacOS compilers */
+#include "ConditionalMacros.h"
+#if TARGET_OS_MAC
+#define FT_MACINTOSH 1
+#endif
+
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* basic_types */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Int16 */
+ /* */
+ /* <Description> */
+ /* A typedef for a 16bit signed integer type. */
+ /* */
+ typedef signed short FT_Int16;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_UInt16 */
+ /* */
+ /* <Description> */
+ /* A typedef for a 16bit unsigned integer type. */
+ /* */
+ typedef unsigned short FT_UInt16;
+
+ /* */
+
+
+ /* this #if 0 ... #endif clause is for documentation purposes */
+#if 0
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Int32 */
+ /* */
+ /* <Description> */
+ /* A typedef for a 32bit signed integer type. The size depends on */
+ /* the configuration. */
+ /* */
+ typedef signed XXX FT_Int32;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_UInt32 */
+ /* */
+ /* A typedef for a 32bit unsigned integer type. The size depends on */
+ /* the configuration. */
+ /* */
+ typedef unsigned XXX FT_UInt32;
+
+ /* */
+
+#endif
+
+#if FT_SIZEOF_INT == (32 / FT_CHAR_BIT)
+
+ typedef signed int FT_Int32;
+ typedef unsigned int FT_UInt32;
+
+#elif FT_SIZEOF_LONG == (32 / FT_CHAR_BIT)
+
+ typedef signed long FT_Int32;
+ typedef unsigned long FT_UInt32;
+
+#else
+#error "no 32bit type found -- please check your configuration files"
+#endif
+
+
+ /* look up an integer type that is at least 32 bits */
+#if FT_SIZEOF_INT >= (32 / FT_CHAR_BIT)
+
+ typedef int FT_Fast;
+ typedef unsigned int FT_UFast;
+
+#elif FT_SIZEOF_LONG >= (32 / FT_CHAR_BIT)
+
+ typedef long FT_Fast;
+ typedef unsigned long FT_UFast;
+
+#endif
+
+
+ /* determine whether we have a 64-bit int type for platforms without */
+ /* Autoconf */
+#if FT_SIZEOF_LONG == (64 / FT_CHAR_BIT)
+
+ /* FT_LONG64 must be defined if a 64-bit type is available */
+#define FT_LONG64
+#define FT_INT64 long
+
+#elif defined( _MSC_VER ) && _MSC_VER >= 900 /* Visual C++ (and Intel C++) */
+
+ /* this compiler provides the __int64 type */
+#define FT_LONG64
+#define FT_INT64 __int64
+
+#elif defined( __BORLANDC__ ) /* Borland C++ */
+
+ /* XXXX: We should probably check the value of __BORLANDC__ in order */
+ /* to test the compiler version. */
+
+ /* this compiler provides the __int64 type */
+#define FT_LONG64
+#define FT_INT64 __int64
+
+#elif defined( __WATCOMC__ ) /* Watcom C++ */
+
+ /* Watcom doesn't provide 64-bit data types */
+
+#elif defined( __MWERKS__ ) /* Metrowerks CodeWarrior */
+
+#define FT_LONG64
+#define FT_INT64 long long int
+
+#elif defined( __GNUC__ )
+
+ /* GCC provides the `long long' type */
+#define FT_LONG64
+#define FT_INT64 long long int
+
+#endif /* FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) */
+
+
+ /*************************************************************************/
+ /* */
+ /* A 64-bit data type will create compilation problems if you compile */
+ /* in strict ANSI mode. To avoid them, we disable its use if __STDC__ */
+ /* is defined. You can however ignore this rule by defining the */
+ /* FT_CONFIG_OPTION_FORCE_INT64 configuration macro. */
+ /* */
+#if defined( FT_LONG64 ) && !defined( FT_CONFIG_OPTION_FORCE_INT64 )
+
+#ifdef __STDC__
+
+ /* undefine the 64-bit macros in strict ANSI compilation mode */
+#undef FT_LONG64
+#undef FT_INT64
+
+#endif /* __STDC__ */
+
+#endif /* FT_LONG64 && !FT_CONFIG_OPTION_FORCE_INT64 */
+
+
+#define FT_BEGIN_STMNT do {
+#define FT_END_STMNT } while ( 0 )
+#define FT_DUMMY_STMNT FT_BEGIN_STMNT FT_END_STMNT
+
+
+#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER
+ /* Provide assembler fragments for performance-critical functions. */
+ /* These must be defined `static __inline__' with GCC. */
+
+#ifdef __GNUC__
+
+#if defined( __arm__ ) && !defined( __thumb__ )
+#define FT_MULFIX_ASSEMBLER FT_MulFix_arm
+
+ /* documentation is in freetype.h */
+
+ static __inline__ FT_Int32
+ FT_MulFix_arm( FT_Int32 a,
+ FT_Int32 b )
+ {
+ register FT_Int32 t, t2;
+
+
+ asm __volatile__ (
+ "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */
+ "mov %0, %2, asr #31\n\t" /* %0 = (hi >> 31) */
+ "add %0, %0, #0x8000\n\t" /* %0 += 0x8000 */
+ "adds %1, %1, %0\n\t" /* %1 += %0 */
+ "adc %2, %2, #0\n\t" /* %2 += carry */
+ "mov %0, %1, lsr #16\n\t" /* %0 = %1 >> 16 */
+ "orr %0, %2, lsl #16\n\t" /* %0 |= %2 << 16 */
+ : "=r"(a), "=&r"(t2), "=&r"(t)
+ : "r"(a), "r"(b) );
+ return a;
+ }
+
+#endif /* __arm__ && !__thumb__ */
+
+#if defined( i386 )
+#define FT_MULFIX_ASSEMBLER FT_MulFix_i386
+
+ /* documentation is in freetype.h */
+
+ static __inline__ FT_Int32
+ FT_MulFix_i386( FT_Int32 a,
+ FT_Int32 b )
+ {
+ register FT_Int32 result;
+
+
+ __asm__ __volatile__ (
+ "imul %%edx\n"
+ "movl %%edx, %%ecx\n"
+ "sarl $31, %%ecx\n"
+ "addl $0x8000, %%ecx\n"
+ "addl %%ecx, %%eax\n"
+ "adcl $0, %%edx\n"
+ "shrl $16, %%eax\n"
+ "shll $16, %%edx\n"
+ "addl %%edx, %%eax\n"
+ : "=a"(result), "=d"(b)
+ : "a"(a), "d"(b)
+ : "%ecx", "cc" );
+ return result;
+ }
+
+#endif /* i386 */
+
+#endif /* __GNUC__ */
+
+#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */
+
+
+#ifdef FT_CONFIG_OPTION_INLINE_MULFIX
+#ifdef FT_MULFIX_ASSEMBLER
+#define FT_MULFIX_INLINED FT_MULFIX_ASSEMBLER
+#endif
+#endif
+
+
+#ifdef FT_MAKE_OPTION_SINGLE_OBJECT
+
+#define FT_LOCAL( x ) static x
+#define FT_LOCAL_DEF( x ) static x
+
+#else
+
+#ifdef __cplusplus
+#define FT_LOCAL( x ) extern "C" x
+#define FT_LOCAL_DEF( x ) extern "C" x
+#else
+#define FT_LOCAL( x ) extern x
+#define FT_LOCAL_DEF( x ) x
+#endif
+
+#endif /* FT_MAKE_OPTION_SINGLE_OBJECT */
+
+
+#ifndef FT_BASE
+
+#ifdef __cplusplus
+#define FT_BASE( x ) extern "C" x
+#else
+#define FT_BASE( x ) extern x
+#endif
+
+#endif /* !FT_BASE */
+
+
+#ifndef FT_BASE_DEF
+
+#ifdef __cplusplus
+#define FT_BASE_DEF( x ) x
+#else
+#define FT_BASE_DEF( x ) x
+#endif
+
+#endif /* !FT_BASE_DEF */
+
+
+#ifndef FT_EXPORT
+
+#ifdef __cplusplus
+#define FT_EXPORT( x ) extern "C" x
+#else
+#define FT_EXPORT( x ) extern x
+#endif
+
+#endif /* !FT_EXPORT */
+
+
+#ifndef FT_EXPORT_DEF
+
+#ifdef __cplusplus
+#define FT_EXPORT_DEF( x ) extern "C" x
+#else
+#define FT_EXPORT_DEF( x ) extern x
+#endif
+
+#endif /* !FT_EXPORT_DEF */
+
+
+#ifndef FT_EXPORT_VAR
+
+#ifdef __cplusplus
+#define FT_EXPORT_VAR( x ) extern "C" x
+#else
+#define FT_EXPORT_VAR( x ) extern x
+#endif
+
+#endif /* !FT_EXPORT_VAR */
+
+ /* The following macros are needed to compile the library with a */
+ /* C++ compiler and with 16bit compilers. */
+ /* */
+
+ /* This is special. Within C++, you must specify `extern "C"' for */
+ /* functions which are used via function pointers, and you also */
+ /* must do that for structures which contain function pointers to */
+ /* assure C linkage -- it's not possible to have (local) anonymous */
+ /* functions which are accessed by (global) function pointers. */
+ /* */
+ /* */
+ /* FT_CALLBACK_DEF is used to _define_ a callback function. */
+ /* */
+ /* FT_CALLBACK_TABLE is used to _declare_ a constant variable that */
+ /* contains pointers to callback functions. */
+ /* */
+ /* FT_CALLBACK_TABLE_DEF is used to _define_ a constant variable */
+ /* that contains pointers to callback functions. */
+ /* */
+ /* */
+ /* Some 16bit compilers have to redefine these macros to insert */
+ /* the infamous `_cdecl' or `__fastcall' declarations. */
+ /* */
+#ifndef FT_CALLBACK_DEF
+#ifdef __cplusplus
+#define FT_CALLBACK_DEF( x ) extern "C" x
+#else
+#define FT_CALLBACK_DEF( x ) static x
+#endif
+#endif /* FT_CALLBACK_DEF */
+
+#ifndef FT_CALLBACK_TABLE
+#ifdef __cplusplus
+#define FT_CALLBACK_TABLE extern "C"
+#define FT_CALLBACK_TABLE_DEF extern "C"
+#else
+#define FT_CALLBACK_TABLE extern
+#define FT_CALLBACK_TABLE_DEF /* nothing */
+#endif
+#endif /* FT_CALLBACK_TABLE */
+
+
+FT_END_HEADER
+
+
+#endif /* __FTCONFIG_H__ */
+
+
+/* END */
diff --git a/guilib/freetype2/include/freetype/config/ftheader.h b/guilib/freetype2/include/freetype/config/ftheader.h
new file mode 100644
index 0000000000..b63945dcbd
--- /dev/null
+++ b/guilib/freetype2/include/freetype/config/ftheader.h
@@ -0,0 +1,780 @@
+/***************************************************************************/
+/* */
+/* ftheader.h */
+/* */
+/* Build macros of the FreeType 2 library. */
+/* */
+/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+#ifndef __FT_HEADER_H__
+#define __FT_HEADER_H__
+
+
+ /*@***********************************************************************/
+ /* */
+ /* <Macro> */
+ /* FT_BEGIN_HEADER */
+ /* */
+ /* <Description> */
+ /* This macro is used in association with @FT_END_HEADER in header */
+ /* files to ensure that the declarations within are properly */
+ /* encapsulated in an `extern "C" { .. }' block when included from a */
+ /* C++ compiler. */
+ /* */
+#ifdef __cplusplus
+#define FT_BEGIN_HEADER extern "C" {
+#else
+#define FT_BEGIN_HEADER /* nothing */
+#endif
+
+
+ /*@***********************************************************************/
+ /* */
+ /* <Macro> */
+ /* FT_END_HEADER */
+ /* */
+ /* <Description> */
+ /* This macro is used in association with @FT_BEGIN_HEADER in header */
+ /* files to ensure that the declarations within are properly */
+ /* encapsulated in an `extern "C" { .. }' block when included from a */
+ /* C++ compiler. */
+ /* */
+#ifdef __cplusplus
+#define FT_END_HEADER }
+#else
+#define FT_END_HEADER /* nothing */
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* Aliases for the FreeType 2 public and configuration files. */
+ /* */
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* header_file_macros */
+ /* */
+ /* <Title> */
+ /* Header File Macros */
+ /* */
+ /* <Abstract> */
+ /* Macro definitions used to #include specific header files. */
+ /* */
+ /* <Description> */
+ /* The following macros are defined to the name of specific */
+ /* FreeType~2 header files. They can be used directly in #include */
+ /* statements as in: */
+ /* */
+ /* { */
+ /* #include FT_FREETYPE_H */
+ /* #include FT_MULTIPLE_MASTERS_H */
+ /* #include FT_GLYPH_H */
+ /* } */
+ /* */
+ /* There are several reasons why we are now using macros to name */
+ /* public header files. The first one is that such macros are not */
+ /* limited to the infamous 8.3~naming rule required by DOS (and */
+ /* `FT_MULTIPLE_MASTERS_H' is a lot more meaningful than `ftmm.h'). */
+ /* */
+ /* The second reason is that it allows for more flexibility in the */
+ /* way FreeType~2 is installed on a given system. */
+ /* */
+ /*************************************************************************/
+
+
+ /* configuration files */
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_CONFIG_CONFIG_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing
+ * FreeType~2 configuration data.
+ *
+ */
+#ifndef FT_CONFIG_CONFIG_H
+#define FT_CONFIG_CONFIG_H <freetype/config/ftconfig.h>
+#endif
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_CONFIG_STANDARD_LIBRARY_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing
+ * FreeType~2 interface to the standard C library functions.
+ *
+ */
+#ifndef FT_CONFIG_STANDARD_LIBRARY_H
+#define FT_CONFIG_STANDARD_LIBRARY_H <freetype/config/ftstdlib.h>
+#endif
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_CONFIG_OPTIONS_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing
+ * FreeType~2 project-specific configuration options.
+ *
+ */
+#ifndef FT_CONFIG_OPTIONS_H
+#define FT_CONFIG_OPTIONS_H <freetype/config/ftoption.h>
+#endif
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_CONFIG_MODULES_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * list of FreeType~2 modules that are statically linked to new library
+ * instances in @FT_Init_FreeType.
+ *
+ */
+#ifndef FT_CONFIG_MODULES_H
+#define FT_CONFIG_MODULES_H <freetype/config/ftmodule.h>
+#endif
+
+ /* */
+
+ /* public headers */
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_FREETYPE_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * base FreeType~2 API.
+ *
+ */
+#define FT_FREETYPE_H <freetype/freetype.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_ERRORS_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * list of FreeType~2 error codes (and messages).
+ *
+ * It is included by @FT_FREETYPE_H.
+ *
+ */
+#define FT_ERRORS_H <freetype/fterrors.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_MODULE_ERRORS_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * list of FreeType~2 module error offsets (and messages).
+ *
+ */
+#define FT_MODULE_ERRORS_H <freetype/ftmoderr.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_SYSTEM_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * FreeType~2 interface to low-level operations (i.e., memory management
+ * and stream i/o).
+ *
+ * It is included by @FT_FREETYPE_H.
+ *
+ */
+#define FT_SYSTEM_H <freetype/ftsystem.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_IMAGE_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing type
+ * definitions related to glyph images (i.e., bitmaps, outlines,
+ * scan-converter parameters).
+ *
+ * It is included by @FT_FREETYPE_H.
+ *
+ */
+#define FT_IMAGE_H <freetype/ftimage.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_TYPES_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * basic data types defined by FreeType~2.
+ *
+ * It is included by @FT_FREETYPE_H.
+ *
+ */
+#define FT_TYPES_H <freetype/fttypes.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_LIST_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * list management API of FreeType~2.
+ *
+ * (Most applications will never need to include this file.)
+ *
+ */
+#define FT_LIST_H <freetype/ftlist.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_OUTLINE_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * scalable outline management API of FreeType~2.
+ *
+ */
+#define FT_OUTLINE_H <freetype/ftoutln.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_SIZES_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * API which manages multiple @FT_Size objects per face.
+ *
+ */
+#define FT_SIZES_H <freetype/ftsizes.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_MODULE_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * module management API of FreeType~2.
+ *
+ */
+#define FT_MODULE_H <freetype/ftmodapi.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_RENDER_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * renderer module management API of FreeType~2.
+ *
+ */
+#define FT_RENDER_H <freetype/ftrender.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_TYPE1_TABLES_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * types and API specific to the Type~1 format.
+ *
+ */
+#define FT_TYPE1_TABLES_H <freetype/t1tables.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_TRUETYPE_IDS_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * enumeration values which identify name strings, languages, encodings,
+ * etc. This file really contains a _large_ set of constant macro
+ * definitions, taken from the TrueType and OpenType specifications.
+ *
+ */
+#define FT_TRUETYPE_IDS_H <freetype/ttnameid.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_TRUETYPE_TABLES_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * types and API specific to the TrueType (as well as OpenType) format.
+ *
+ */
+#define FT_TRUETYPE_TABLES_H <freetype/tttables.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_TRUETYPE_TAGS_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * definitions of TrueType four-byte `tags' which identify blocks in
+ * SFNT-based font formats (i.e., TrueType and OpenType).
+ *
+ */
+#define FT_TRUETYPE_TAGS_H <freetype/tttags.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_BDF_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * definitions of an API which accesses BDF-specific strings from a
+ * face.
+ *
+ */
+#define FT_BDF_H <freetype/ftbdf.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_CID_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * definitions of an API which access CID font information from a
+ * face.
+ *
+ */
+#define FT_CID_H <freetype/ftcid.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_GZIP_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * definitions of an API which supports gzip-compressed files.
+ *
+ */
+#define FT_GZIP_H <freetype/ftgzip.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_LZW_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * definitions of an API which supports LZW-compressed files.
+ *
+ */
+#define FT_LZW_H <freetype/ftlzw.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_WINFONTS_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * definitions of an API which supports Windows FNT files.
+ *
+ */
+#define FT_WINFONTS_H <freetype/ftwinfnt.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_GLYPH_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * API of the optional glyph management component.
+ *
+ */
+#define FT_GLYPH_H <freetype/ftglyph.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_BITMAP_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * API of the optional bitmap conversion component.
+ *
+ */
+#define FT_BITMAP_H <freetype/ftbitmap.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_BBOX_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * API of the optional exact bounding box computation routines.
+ *
+ */
+#define FT_BBOX_H <freetype/ftbbox.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_CACHE_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * API of the optional FreeType~2 cache sub-system.
+ *
+ */
+#define FT_CACHE_H <freetype/ftcache.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_CACHE_IMAGE_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * `glyph image' API of the FreeType~2 cache sub-system.
+ *
+ * It is used to define a cache for @FT_Glyph elements. You can also
+ * use the API defined in @FT_CACHE_SMALL_BITMAPS_H if you only need to
+ * store small glyph bitmaps, as it will use less memory.
+ *
+ * This macro is deprecated. Simply include @FT_CACHE_H to have all
+ * glyph image-related cache declarations.
+ *
+ */
+#define FT_CACHE_IMAGE_H FT_CACHE_H
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_CACHE_SMALL_BITMAPS_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * `small bitmaps' API of the FreeType~2 cache sub-system.
+ *
+ * It is used to define a cache for small glyph bitmaps in a relatively
+ * memory-efficient way. You can also use the API defined in
+ * @FT_CACHE_IMAGE_H if you want to cache arbitrary glyph images,
+ * including scalable outlines.
+ *
+ * This macro is deprecated. Simply include @FT_CACHE_H to have all
+ * small bitmaps-related cache declarations.
+ *
+ */
+#define FT_CACHE_SMALL_BITMAPS_H FT_CACHE_H
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_CACHE_CHARMAP_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * `charmap' API of the FreeType~2 cache sub-system.
+ *
+ * This macro is deprecated. Simply include @FT_CACHE_H to have all
+ * charmap-based cache declarations.
+ *
+ */
+#define FT_CACHE_CHARMAP_H FT_CACHE_H
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_MAC_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * Macintosh-specific FreeType~2 API. The latter is used to access
+ * fonts embedded in resource forks.
+ *
+ * This header file must be explicitly included by client applications
+ * compiled on the Mac (note that the base API still works though).
+ *
+ */
+#define FT_MAC_H <freetype/ftmac.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_MULTIPLE_MASTERS_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * optional multiple-masters management API of FreeType~2.
+ *
+ */
+#define FT_MULTIPLE_MASTERS_H <freetype/ftmm.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_SFNT_NAMES_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * optional FreeType~2 API which accesses embedded `name' strings in
+ * SFNT-based font formats (i.e., TrueType and OpenType).
+ *
+ */
+#define FT_SFNT_NAMES_H <freetype/ftsnames.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_OPENTYPE_VALIDATE_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * optional FreeType~2 API which validates OpenType tables (BASE, GDEF,
+ * GPOS, GSUB, JSTF).
+ *
+ */
+#define FT_OPENTYPE_VALIDATE_H <freetype/ftotval.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_GX_VALIDATE_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * optional FreeType~2 API which validates TrueTypeGX/AAT tables (feat,
+ * mort, morx, bsln, just, kern, opbd, trak, prop).
+ *
+ */
+#define FT_GX_VALIDATE_H <freetype/ftgxval.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_PFR_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * FreeType~2 API which accesses PFR-specific data.
+ *
+ */
+#define FT_PFR_H <freetype/ftpfr.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_STROKER_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * FreeType~2 API which provides functions to stroke outline paths.
+ */
+#define FT_STROKER_H <freetype/ftstroke.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_SYNTHESIS_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * FreeType~2 API which performs artificial obliquing and emboldening.
+ */
+#define FT_SYNTHESIS_H <freetype/ftsynth.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_XFREE86_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * FreeType~2 API which provides functions specific to the XFree86 and
+ * X.Org X11 servers.
+ */
+#define FT_XFREE86_H <freetype/ftxf86.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_TRIGONOMETRY_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * FreeType~2 API which performs trigonometric computations (e.g.,
+ * cosines and arc tangents).
+ */
+#define FT_TRIGONOMETRY_H <freetype/fttrigon.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_LCD_FILTER_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * FreeType~2 API which performs color filtering for subpixel rendering.
+ */
+#define FT_LCD_FILTER_H <freetype/ftlcdfil.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_UNPATENTED_HINTING_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * FreeType~2 API which performs color filtering for subpixel rendering.
+ */
+#define FT_UNPATENTED_HINTING_H <freetype/ttunpat.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_INCREMENTAL_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * FreeType~2 API which performs color filtering for subpixel rendering.
+ */
+#define FT_INCREMENTAL_H <freetype/ftincrem.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_GASP_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * FreeType~2 API which returns entries from the TrueType GASP table.
+ */
+#define FT_GASP_H <freetype/ftgasp.h>
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_ADVANCES_H
+ *
+ * @description:
+ * A macro used in #include statements to name the file containing the
+ * FreeType~2 API which returns individual and ranged glyph advances.
+ */
+#define FT_ADVANCES_H <freetype/ftadvanc.h>
+
+
+ /* */
+
+#define FT_ERROR_DEFINITIONS_H <freetype/fterrdef.h>
+
+
+ /* The internals of the cache sub-system are no longer exposed. We */
+ /* default to FT_CACHE_H at the moment just in case, but we know of */
+ /* no rogue client that uses them. */
+ /* */
+#define FT_CACHE_MANAGER_H <freetype/ftcache.h>
+#define FT_CACHE_INTERNAL_MRU_H <freetype/ftcache.h>
+#define FT_CACHE_INTERNAL_MANAGER_H <freetype/ftcache.h>
+#define FT_CACHE_INTERNAL_CACHE_H <freetype/ftcache.h>
+#define FT_CACHE_INTERNAL_GLYPH_H <freetype/ftcache.h>
+#define FT_CACHE_INTERNAL_IMAGE_H <freetype/ftcache.h>
+#define FT_CACHE_INTERNAL_SBITS_H <freetype/ftcache.h>
+
+
+#define FT_INCREMENTAL_H <freetype/ftincrem.h>
+
+#define FT_TRUETYPE_UNPATENTED_H <freetype/ttunpat.h>
+
+
+ /*
+ * Include internal headers definitions from <freetype/internal/...>
+ * only when building the library.
+ */
+#ifdef FT2_BUILD_LIBRARY
+#define FT_INTERNAL_INTERNAL_H <freetype/internal/internal.h>
+#include FT_INTERNAL_INTERNAL_H
+#endif /* FT2_BUILD_LIBRARY */
+
+
+#endif /* __FT2_BUILD_H__ */
+
+
+/* END */
diff --git a/guilib/freetype2/include/freetype/config/ftoption.h b/guilib/freetype2/include/freetype/config/ftoption.h
new file mode 100644
index 0000000000..597a2bb014
--- /dev/null
+++ b/guilib/freetype2/include/freetype/config/ftoption.h
@@ -0,0 +1,693 @@
+/***************************************************************************/
+/* */
+/* ftoption.h */
+/* */
+/* User-selectable configuration macros (specification only). */
+/* */
+/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTOPTION_H__
+#define __FTOPTION_H__
+
+
+#include <ft2build.h>
+
+
+FT_BEGIN_HEADER
+
+ /*************************************************************************/
+ /* */
+ /* USER-SELECTABLE CONFIGURATION MACROS */
+ /* */
+ /* This file contains the default configuration macro definitions for */
+ /* a standard build of the FreeType library. There are three ways to */
+ /* use this file to build project-specific versions of the library: */
+ /* */
+ /* - You can modify this file by hand, but this is not recommended in */
+ /* cases where you would like to build several versions of the */
+ /* library from a single source directory. */
+ /* */
+ /* - You can put a copy of this file in your build directory, more */
+ /* precisely in `$BUILD/freetype/config/ftoption.h', where `$BUILD' */
+ /* is the name of a directory that is included _before_ the FreeType */
+ /* include path during compilation. */
+ /* */
+ /* The default FreeType Makefiles and Jamfiles use the build */
+ /* directory `builds/<system>' by default, but you can easily change */
+ /* that for your own projects. */
+ /* */
+ /* - Copy the file <ft2build.h> to `$BUILD/ft2build.h' and modify it */
+ /* slightly to pre-define the macro FT_CONFIG_OPTIONS_H used to */
+ /* locate this file during the build. For example, */
+ /* */
+ /* #define FT_CONFIG_OPTIONS_H <myftoptions.h> */
+ /* #include <freetype/config/ftheader.h> */
+ /* */
+ /* will use `$BUILD/myftoptions.h' instead of this file for macro */
+ /* definitions. */
+ /* */
+ /* Note also that you can similarly pre-define the macro */
+ /* FT_CONFIG_MODULES_H used to locate the file listing of the modules */
+ /* that are statically linked to the library at compile time. By */
+ /* default, this file is <freetype/config/ftmodule.h>. */
+ /* */
+ /* We highly recommend using the third method whenever possible. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** G E N E R A L F R E E T Y P E 2 C O N F I G U R A T I O N ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Uncomment the line below if you want to activate sub-pixel rendering */
+ /* (a.k.a. LCD rendering, or ClearType) in this build of the library. */
+ /* */
+ /* Note that this feature is covered by several Microsoft patents */
+ /* and should not be activated in any default build of the library. */
+ /* */
+ /* This macro has no impact on the FreeType API, only on its */
+ /* _implementation_. For example, using FT_RENDER_MODE_LCD when calling */
+ /* FT_Render_Glyph still generates a bitmap that is 3 times larger than */
+ /* the original size; the difference will be that each triplet of */
+ /* subpixels has R=G=B. */
+ /* */
+ /* This is done to allow FreeType clients to run unmodified, forcing */
+ /* them to display normal gray-level anti-aliased glyphs. */
+ /* */
+/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+
+
+ /*************************************************************************/
+ /* */
+ /* Many compilers provide a non-ANSI 64-bit data type that can be used */
+ /* by FreeType to speed up some computations. However, this will create */
+ /* some problems when compiling the library in strict ANSI mode. */
+ /* */
+ /* For this reason, the use of 64-bit integers is normally disabled when */
+ /* the __STDC__ macro is defined. You can however disable this by */
+ /* defining the macro FT_CONFIG_OPTION_FORCE_INT64 here. */
+ /* */
+ /* For most compilers, this will only create compilation warnings when */
+ /* building the library. */
+ /* */
+ /* ObNote: The compiler-specific 64-bit integers are detected in the */
+ /* file `ftconfig.h' either statically or through the */
+ /* `configure' script on supported platforms. */
+ /* */
+#undef FT_CONFIG_OPTION_FORCE_INT64
+
+
+ /*************************************************************************/
+ /* */
+ /* If this macro is defined, do not try to use an assembler version of */
+ /* performance-critical functions (e.g. FT_MulFix). You should only do */
+ /* that to verify that the assembler function works properly, or to */
+ /* execute benchmark tests of the various implementations. */
+/* #define FT_CONFIG_OPTION_NO_ASSEMBLER */
+
+
+ /*************************************************************************/
+ /* */
+ /* If this macro is defined, try to use an inlined assembler version of */
+ /* the `FT_MulFix' function, which is a `hotspot' when loading and */
+ /* hinting glyphs, and which should be executed as fast as possible. */
+ /* */
+ /* Note that if your compiler or CPU is not supported, this will default */
+ /* to the standard and portable implementation found in `ftcalc.c'. */
+ /* */
+#define FT_CONFIG_OPTION_INLINE_MULFIX
+
+
+ /*************************************************************************/
+ /* */
+ /* LZW-compressed file support. */
+ /* */
+ /* FreeType now handles font files that have been compressed with the */
+ /* `compress' program. This is mostly used to parse many of the PCF */
+ /* files that come with various X11 distributions. The implementation */
+ /* uses NetBSD's `zopen' to partially uncompress the file on the fly */
+ /* (see src/lzw/ftgzip.c). */
+ /* */
+ /* Define this macro if you want to enable this `feature'. */
+ /* */
+#define FT_CONFIG_OPTION_USE_LZW
+
+
+ /*************************************************************************/
+ /* */
+ /* Gzip-compressed file support. */
+ /* */
+ /* FreeType now handles font files that have been compressed with the */
+ /* `gzip' program. This is mostly used to parse many of the PCF files */
+ /* that come with XFree86. The implementation uses `zlib' to */
+ /* partially uncompress the file on the fly (see src/gzip/ftgzip.c). */
+ /* */
+ /* Define this macro if you want to enable this `feature'. See also */
+ /* the macro FT_CONFIG_OPTION_SYSTEM_ZLIB below. */
+ /* */
+#define FT_CONFIG_OPTION_USE_ZLIB
+
+
+ /*************************************************************************/
+ /* */
+ /* ZLib library selection */
+ /* */
+ /* This macro is only used when FT_CONFIG_OPTION_USE_ZLIB is defined. */
+ /* It allows FreeType's `ftgzip' component to link to the system's */
+ /* installation of the ZLib library. This is useful on systems like */
+ /* Unix or VMS where it generally is already available. */
+ /* */
+ /* If you let it undefined, the component will use its own copy */
+ /* of the zlib sources instead. These have been modified to be */
+ /* included directly within the component and *not* export external */
+ /* function names. This allows you to link any program with FreeType */
+ /* _and_ ZLib without linking conflicts. */
+ /* */
+ /* Do not #undef this macro here since the build system might define */
+ /* it for certain configurations only. */
+ /* */
+/* #define FT_CONFIG_OPTION_SYSTEM_ZLIB */
+
+
+ /*************************************************************************/
+ /* */
+ /* DLL export compilation */
+ /* */
+ /* When compiling FreeType as a DLL, some systems/compilers need a */
+ /* special keyword in front OR after the return type of function */
+ /* declarations. */
+ /* */
+ /* Two macros are used within the FreeType source code to define */
+ /* exported library functions: FT_EXPORT and FT_EXPORT_DEF. */
+ /* */
+ /* FT_EXPORT( return_type ) */
+ /* */
+ /* is used in a function declaration, as in */
+ /* */
+ /* FT_EXPORT( FT_Error ) */
+ /* FT_Init_FreeType( FT_Library* alibrary ); */
+ /* */
+ /* */
+ /* FT_EXPORT_DEF( return_type ) */
+ /* */
+ /* is used in a function definition, as in */
+ /* */
+ /* FT_EXPORT_DEF( FT_Error ) */
+ /* FT_Init_FreeType( FT_Library* alibrary ) */
+ /* { */
+ /* ... some code ... */
+ /* return FT_Err_Ok; */
+ /* } */
+ /* */
+ /* You can provide your own implementation of FT_EXPORT and */
+ /* FT_EXPORT_DEF here if you want. If you leave them undefined, they */
+ /* will be later automatically defined as `extern return_type' to */
+ /* allow normal compilation. */
+ /* */
+ /* Do not #undef these macros here since the build system might define */
+ /* them for certain configurations only. */
+ /* */
+/* #define FT_EXPORT(x) extern x */
+/* #define FT_EXPORT_DEF(x) x */
+
+
+ /*************************************************************************/
+ /* */
+ /* Glyph Postscript Names handling */
+ /* */
+ /* By default, FreeType 2 is compiled with the `psnames' module. This */
+ /* module is in charge of converting a glyph name string into a */
+ /* Unicode value, or return a Macintosh standard glyph name for the */
+ /* use with the TrueType `post' table. */
+ /* */
+ /* Undefine this macro if you do not want `psnames' compiled in your */
+ /* build of FreeType. This has the following effects: */
+ /* */
+ /* - The TrueType driver will provide its own set of glyph names, */
+ /* if you build it to support postscript names in the TrueType */
+ /* `post' table. */
+ /* */
+ /* - The Type 1 driver will not be able to synthesize a Unicode */
+ /* charmap out of the glyphs found in the fonts. */
+ /* */
+ /* You would normally undefine this configuration macro when building */
+ /* a version of FreeType that doesn't contain a Type 1 or CFF driver. */
+ /* */
+#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+
+ /*************************************************************************/
+ /* */
+ /* Postscript Names to Unicode Values support */
+ /* */
+ /* By default, FreeType 2 is built with the `PSNames' module compiled */
+ /* in. Among other things, the module is used to convert a glyph name */
+ /* into a Unicode value. This is especially useful in order to */
+ /* synthesize on the fly a Unicode charmap from the CFF/Type 1 driver */
+ /* through a big table named the `Adobe Glyph List' (AGL). */
+ /* */
+ /* Undefine this macro if you do not want the Adobe Glyph List */
+ /* compiled in your `PSNames' module. The Type 1 driver will not be */
+ /* able to synthesize a Unicode charmap out of the glyphs found in the */
+ /* fonts. */
+ /* */
+#define FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+
+ /*************************************************************************/
+ /* */
+ /* Support for Mac fonts */
+ /* */
+ /* Define this macro if you want support for outline fonts in Mac */
+ /* format (mac dfont, mac resource, macbinary containing a mac */
+ /* resource) on non-Mac platforms. */
+ /* */
+ /* Note that the `FOND' resource isn't checked. */
+ /* */
+#define FT_CONFIG_OPTION_MAC_FONTS
+
+
+ /*************************************************************************/
+ /* */
+ /* Guessing methods to access embedded resource forks */
+ /* */
+ /* Enable extra Mac fonts support on non-Mac platforms (e.g. */
+ /* GNU/Linux). */
+ /* */
+ /* Resource forks which include fonts data are stored sometimes in */
+ /* locations which users or developers don't expected. In some cases, */
+ /* resource forks start with some offset from the head of a file. In */
+ /* other cases, the actual resource fork is stored in file different */
+ /* from what the user specifies. If this option is activated, */
+ /* FreeType tries to guess whether such offsets or different file */
+ /* names must be used. */
+ /* */
+ /* Note that normal, direct access of resource forks is controlled via */
+ /* the FT_CONFIG_OPTION_MAC_FONTS option. */
+ /* */
+#ifdef FT_CONFIG_OPTION_MAC_FONTS
+#define FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* Allow the use of FT_Incremental_Interface to load typefaces that */
+ /* contain no glyph data, but supply it via a callback function. */
+ /* This allows FreeType to be used with the PostScript language, using */
+ /* the GhostScript interpreter. */
+ /* */
+/* #define FT_CONFIG_OPTION_INCREMENTAL */
+
+
+ /*************************************************************************/
+ /* */
+ /* The size in bytes of the render pool used by the scan-line converter */
+ /* to do all of its work. */
+ /* */
+ /* This must be greater than 4KByte if you use FreeType to rasterize */
+ /* glyphs; otherwise, you may set it to zero to avoid unnecessary */
+ /* allocation of the render pool. */
+ /* */
+#define FT_RENDER_POOL_SIZE 16384L
+
+
+ /*************************************************************************/
+ /* */
+ /* FT_MAX_MODULES */
+ /* */
+ /* The maximum number of modules that can be registered in a single */
+ /* FreeType library object. 32 is the default. */
+ /* */
+#define FT_MAX_MODULES 32
+
+
+ /*************************************************************************/
+ /* */
+ /* Debug level */
+ /* */
+ /* FreeType can be compiled in debug or trace mode. In debug mode, */
+ /* errors are reported through the `ftdebug' component. In trace */
+ /* mode, additional messages are sent to the standard output during */
+ /* execution. */
+ /* */
+ /* Define FT_DEBUG_LEVEL_ERROR to build the library in debug mode. */
+ /* Define FT_DEBUG_LEVEL_TRACE to build it in trace mode. */
+ /* */
+ /* Don't define any of these macros to compile in `release' mode! */
+ /* */
+ /* Do not #undef these macros here since the build system might define */
+ /* them for certain configurations only. */
+ /* */
+/* #define FT_DEBUG_LEVEL_ERROR */
+/* #define FT_DEBUG_LEVEL_TRACE */
+
+
+ /*************************************************************************/
+ /* */
+ /* Memory Debugging */
+ /* */
+ /* FreeType now comes with an integrated memory debugger that is */
+ /* capable of detecting simple errors like memory leaks or double */
+ /* deletes. To compile it within your build of the library, you */
+ /* should define FT_DEBUG_MEMORY here. */
+ /* */
+ /* Note that the memory debugger is only activated at runtime when */
+ /* when the _environment_ variable `FT2_DEBUG_MEMORY' is defined also! */
+ /* */
+ /* Do not #undef this macro here since the build system might define */
+ /* it for certain configurations only. */
+ /* */
+/* #define FT_DEBUG_MEMORY */
+
+
+ /*************************************************************************/
+ /* */
+ /* Module errors */
+ /* */
+ /* If this macro is set (which is _not_ the default), the higher byte */
+ /* of an error code gives the module in which the error has occurred, */
+ /* while the lower byte is the real error code. */
+ /* */
+ /* Setting this macro makes sense for debugging purposes only, since */
+ /* it would break source compatibility of certain programs that use */
+ /* FreeType 2. */
+ /* */
+ /* More details can be found in the files ftmoderr.h and fterrors.h. */
+ /* */
+#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS
+
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** S F N T D R I V E R C O N F I G U R A T I O N ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Define TT_CONFIG_OPTION_EMBEDDED_BITMAPS if you want to support */
+ /* embedded bitmaps in all formats using the SFNT module (namely */
+ /* TrueType & OpenType). */
+ /* */
+#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+
+ /*************************************************************************/
+ /* */
+ /* Define TT_CONFIG_OPTION_POSTSCRIPT_NAMES if you want to be able to */
+ /* load and enumerate the glyph Postscript names in a TrueType or */
+ /* OpenType file. */
+ /* */
+ /* Note that when you do not compile the `PSNames' module by undefining */
+ /* the above FT_CONFIG_OPTION_POSTSCRIPT_NAMES, the `sfnt' module will */
+ /* contain additional code used to read the PS Names table from a font. */
+ /* */
+ /* (By default, the module uses `PSNames' to extract glyph names.) */
+ /* */
+#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+
+ /*************************************************************************/
+ /* */
+ /* Define TT_CONFIG_OPTION_SFNT_NAMES if your applications need to */
+ /* access the internal name table in a SFNT-based format like TrueType */
+ /* or OpenType. The name table contains various strings used to */
+ /* describe the font, like family name, copyright, version, etc. It */
+ /* does not contain any glyph name though. */
+ /* */
+ /* Accessing SFNT names is done through the functions declared in */
+ /* `freetype/ftnames.h'. */
+ /* */
+#define TT_CONFIG_OPTION_SFNT_NAMES
+
+
+ /*************************************************************************/
+ /* */
+ /* TrueType CMap support */
+ /* */
+ /* Here you can fine-tune which TrueType CMap table format shall be */
+ /* supported. */
+#define TT_CONFIG_CMAP_FORMAT_0
+#define TT_CONFIG_CMAP_FORMAT_2
+#define TT_CONFIG_CMAP_FORMAT_4
+#define TT_CONFIG_CMAP_FORMAT_6
+#define TT_CONFIG_CMAP_FORMAT_8
+#define TT_CONFIG_CMAP_FORMAT_10
+#define TT_CONFIG_CMAP_FORMAT_12
+#define TT_CONFIG_CMAP_FORMAT_14
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** T R U E T Y P E D R I V E R C O N F I G U R A T I O N ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* Define TT_CONFIG_OPTION_BYTECODE_INTERPRETER if you want to compile */
+ /* a bytecode interpreter in the TrueType driver. Note that there are */
+ /* important patent issues related to the use of the interpreter. */
+ /* */
+ /* By undefining this, you will only compile the code necessary to load */
+ /* TrueType glyphs without hinting. */
+ /* */
+ /* Do not #undef this macro here, since the build system might */
+ /* define it for certain configurations only. */
+ /* */
+/* #define TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+
+ /*************************************************************************/
+ /* */
+ /* If you define TT_CONFIG_OPTION_UNPATENTED_HINTING, a special version */
+ /* of the TrueType bytecode interpreter is used that doesn't implement */
+ /* any of the patented opcodes and algorithms. Note that the */
+ /* TT_CONFIG_OPTION_UNPATENTED_HINTING macro is *ignored* if you define */
+ /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER; in other words, either define */
+ /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER or */
+ /* TT_CONFIG_OPTION_UNPATENTED_HINTING but not both at the same time. */
+ /* */
+ /* This macro is only useful for a small number of font files (mostly */
+ /* for Asian scripts) that require bytecode interpretation to properly */
+ /* load glyphs. For all other fonts, this produces unpleasant results, */
+ /* thus the unpatented interpreter is never used to load glyphs from */
+ /* TrueType fonts unless one of the following two options is used. */
+ /* */
+ /* - The unpatented interpreter is explicitly activated by the user */
+ /* through the FT_PARAM_TAG_UNPATENTED_HINTING parameter tag */
+ /* when opening the FT_Face. */
+ /* */
+ /* - FreeType detects that the FT_Face corresponds to one of the */
+ /* `trick' fonts (e.g., `Mingliu') it knows about. The font engine */
+ /* contains a hard-coded list of font names and other matching */
+ /* parameters (see function `tt_face_init' in file */
+ /* `src/truetype/ttobjs.c'). */
+ /* */
+ /* Here a sample code snippet for using FT_PARAM_TAG_UNPATENTED_HINTING. */
+ /* */
+ /* { */
+ /* FT_Parameter parameter; */
+ /* FT_Open_Args open_args; */
+ /* */
+ /* */
+ /* parameter.tag = FT_PARAM_TAG_UNPATENTED_HINTING; */
+ /* */
+ /* open_args.flags = FT_OPEN_PATHNAME | FT_OPEN_PARAMS; */
+ /* open_args.pathname = my_font_pathname; */
+ /* open_args.num_params = 1; */
+ /* open_args.params = &parameter; */
+ /* */
+ /* error = FT_Open_Face( library, &open_args, index, &face ); */
+ /* ... */
+ /* } */
+ /* */
+#define TT_CONFIG_OPTION_UNPATENTED_HINTING
+
+
+ /*************************************************************************/
+ /* */
+ /* Define TT_CONFIG_OPTION_INTERPRETER_SWITCH to compile the TrueType */
+ /* bytecode interpreter with a huge switch statement, rather than a call */
+ /* table. This results in smaller and faster code for a number of */
+ /* architectures. */
+ /* */
+ /* Note however that on some compiler/processor combinations, undefining */
+ /* this macro will generate faster, though larger, code. */
+ /* */
+#define TT_CONFIG_OPTION_INTERPRETER_SWITCH
+
+
+ /*************************************************************************/
+ /* */
+ /* Define TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED to compile the */
+ /* TrueType glyph loader to use Apple's definition of how to handle */
+ /* component offsets in composite glyphs. */
+ /* */
+ /* Apple and MS disagree on the default behavior of component offsets */
+ /* in composites. Apple says that they should be scaled by the scaling */
+ /* factors in the transformation matrix (roughly, it's more complex) */
+ /* while MS says they should not. OpenType defines two bits in the */
+ /* composite flags array which can be used to disambiguate, but old */
+ /* fonts will not have them. */
+ /* */
+ /* http://partners.adobe.com/asn/developer/opentype/glyf.html */
+ /* http://fonts.apple.com/TTRefMan/RM06/Chap6glyf.html */
+ /* */
+#undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED
+
+
+ /*************************************************************************/
+ /* */
+ /* Define TT_CONFIG_OPTION_GX_VAR_SUPPORT if you want to include */
+ /* support for Apple's distortable font technology (fvar, gvar, cvar, */
+ /* and avar tables). This has many similarities to Type 1 Multiple */
+ /* Masters support. */
+ /* */
+#define TT_CONFIG_OPTION_GX_VAR_SUPPORT
+
+
+ /*************************************************************************/
+ /* */
+ /* Define TT_CONFIG_OPTION_BDF if you want to include support for */
+ /* an embedded `BDF ' table within SFNT-based bitmap formats. */
+ /* */
+#define TT_CONFIG_OPTION_BDF
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** T Y P E 1 D R I V E R C O N F I G U R A T I O N ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* T1_MAX_DICT_DEPTH is the maximal depth of nest dictionaries and */
+ /* arrays in the Type 1 stream (see t1load.c). A minimum of 4 is */
+ /* required. */
+ /* */
+#define T1_MAX_DICT_DEPTH 5
+
+
+ /*************************************************************************/
+ /* */
+ /* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine */
+ /* calls during glyph loading. */
+ /* */
+#define T1_MAX_SUBRS_CALLS 16
+
+
+ /*************************************************************************/
+ /* */
+ /* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. A */
+ /* minimum of 16 is required. */
+ /* */
+ /* The Chinese font MingTiEG-Medium (CNS 11643 character set) needs 256. */
+ /* */
+#define T1_MAX_CHARSTRINGS_OPERANDS 256
+
+
+ /*************************************************************************/
+ /* */
+ /* Define this configuration macro if you want to prevent the */
+ /* compilation of `t1afm', which is in charge of reading Type 1 AFM */
+ /* files into an existing face. Note that if set, the T1 driver will be */
+ /* unable to produce kerning distances. */
+ /* */
+#undef T1_CONFIG_OPTION_NO_AFM
+
+
+ /*************************************************************************/
+ /* */
+ /* Define this configuration macro if you want to prevent the */
+ /* compilation of the Multiple Masters font support in the Type 1 */
+ /* driver. */
+ /* */
+#undef T1_CONFIG_OPTION_NO_MM_SUPPORT
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** A U T O F I T M O D U L E C O N F I G U R A T I O N ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Compile autofit module with CJK (Chinese, Japanese, Korean) script */
+ /* support. */
+ /* */
+#define AF_CONFIG_OPTION_CJK
+
+ /*************************************************************************/
+ /* */
+ /* Compile autofit module with Indic script support. */
+ /* */
+#define AF_CONFIG_OPTION_INDIC
+
+ /* */
+
+
+ /*
+ * Define this variable if you want to keep the layout of internal
+ * structures that was used prior to FreeType 2.2. This also compiles in
+ * a few obsolete functions to avoid linking problems on typical Unix
+ * distributions.
+ *
+ * For embedded systems or building a new distribution from scratch, it
+ * is recommended to disable the macro since it reduces the library's code
+ * size and activates a few memory-saving optimizations as well.
+ */
+#define FT_CONFIG_OPTION_OLD_INTERNALS
+
+
+ /*
+ * This macro is defined if either unpatented or native TrueType
+ * hinting is requested by the definitions above.
+ */
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+#define TT_USE_BYTECODE_INTERPRETER
+#undef TT_CONFIG_OPTION_UNPATENTED_HINTING
+#elif defined TT_CONFIG_OPTION_UNPATENTED_HINTING
+#define TT_USE_BYTECODE_INTERPRETER
+#endif
+
+FT_END_HEADER
+
+
+#endif /* __FTOPTION_H__ */
+
+
+/* END */
diff --git a/guilib/freetype2/include/freetype/config/ftstdlib.h b/guilib/freetype2/include/freetype/config/ftstdlib.h
new file mode 100644
index 0000000000..ce5557aef3
--- /dev/null
+++ b/guilib/freetype2/include/freetype/config/ftstdlib.h
@@ -0,0 +1,172 @@
+/***************************************************************************/
+/* */
+/* ftstdlib.h */
+/* */
+/* ANSI-specific library and header configuration file (specification */
+/* only). */
+/* */
+/* Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2009 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to group all #includes to the ANSI C library that */
+ /* FreeType normally requires. It also defines macros to rename the */
+ /* standard functions within the FreeType source code. */
+ /* */
+ /* Load a file which defines __FTSTDLIB_H__ before this one to override */
+ /* it. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTSTDLIB_H__
+#define __FTSTDLIB_H__
+
+
+#include <stddef.h>
+
+#define ft_ptrdiff_t ptrdiff_t
+
+
+ /**********************************************************************/
+ /* */
+ /* integer limits */
+ /* */
+ /* UINT_MAX and ULONG_MAX are used to automatically compute the size */
+ /* of `int' and `long' in bytes at compile-time. So far, this works */
+ /* for all platforms the library has been tested on. */
+ /* */
+ /* Note that on the extremely rare platforms that do not provide */
+ /* integer types that are _exactly_ 16 and 32 bits wide (e.g. some */
+ /* old Crays where `int' is 36 bits), we do not make any guarantee */
+ /* about the correct behaviour of FT2 with all fonts. */
+ /* */
+ /* In these case, `ftconfig.h' will refuse to compile anyway with a */
+ /* message like `couldn't find 32-bit type' or something similar. */
+ /* */
+ /**********************************************************************/
+
+
+#include <limits.h>
+
+#define FT_CHAR_BIT CHAR_BIT
+#define FT_INT_MAX INT_MAX
+#define FT_UINT_MAX UINT_MAX
+#define FT_ULONG_MAX ULONG_MAX
+
+
+ /**********************************************************************/
+ /* */
+ /* character and string processing */
+ /* */
+ /**********************************************************************/
+
+
+#include <string.h>
+
+#define ft_memchr memchr
+#define ft_memcmp memcmp
+#define ft_memcpy memcpy
+#define ft_memmove memmove
+#define ft_memset memset
+#define ft_strcat strcat
+#define ft_strcmp strcmp
+#define ft_strcpy strcpy
+#define ft_strlen strlen
+#define ft_strncmp strncmp
+#define ft_strncpy strncpy
+#define ft_strrchr strrchr
+#define ft_strstr strstr
+
+
+ /**********************************************************************/
+ /* */
+ /* file handling */
+ /* */
+ /**********************************************************************/
+
+
+#include <stdio.h>
+
+#define FT_FILE FILE
+#define ft_fclose fclose
+#define ft_fopen fopen
+#define ft_fread fread
+#define ft_fseek fseek
+#define ft_ftell ftell
+#define ft_sprintf sprintf
+
+
+ /**********************************************************************/
+ /* */
+ /* sorting */
+ /* */
+ /**********************************************************************/
+
+
+#include <stdlib.h>
+
+#define ft_qsort qsort
+
+
+ /**********************************************************************/
+ /* */
+ /* memory allocation */
+ /* */
+ /**********************************************************************/
+
+
+#define ft_scalloc calloc
+#define ft_sfree free
+#define ft_smalloc malloc
+#define ft_srealloc realloc
+
+
+ /**********************************************************************/
+ /* */
+ /* miscellaneous */
+ /* */
+ /**********************************************************************/
+
+
+#define ft_atol atol
+#define ft_labs labs
+
+
+ /**********************************************************************/
+ /* */
+ /* execution control */
+ /* */
+ /**********************************************************************/
+
+
+#include <setjmp.h>
+
+#define ft_jmp_buf jmp_buf /* note: this cannot be a typedef since */
+ /* jmp_buf is defined as a macro */
+ /* on certain platforms */
+
+#define ft_longjmp longjmp
+#define ft_setjmp( b ) setjmp( *(jmp_buf*) &(b) ) /* same thing here */
+
+
+ /* the following is only used for debugging purposes, i.e., if */
+ /* FT_DEBUG_LEVEL_ERROR or FT_DEBUG_LEVEL_TRACE are defined */
+
+#include <stdarg.h>
+
+
+#endif /* __FTSTDLIB_H__ */
+
+
+/* END */
diff --git a/guilib/freetype2/include/freetype/freetype.h b/guilib/freetype2/include/freetype/freetype.h
new file mode 100644
index 0000000000..364388b5d6
--- /dev/null
+++ b/guilib/freetype2/include/freetype/freetype.h
@@ -0,0 +1,3862 @@
+/***************************************************************************/
+/* */
+/* freetype.h */
+/* */
+/* FreeType high-level API and common types (specification only). */
+/* */
+/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef FT_FREETYPE_H
+#error "`ft2build.h' hasn't been included yet!"
+#error "Please always use macros to include FreeType header files."
+#error "Example:"
+#error " #include <ft2build.h>"
+#error " #include FT_FREETYPE_H"
+#endif
+
+
+#ifndef __FREETYPE_H__
+#define __FREETYPE_H__
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_ERRORS_H
+#include FT_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* user_allocation */
+ /* */
+ /* <Title> */
+ /* User allocation */
+ /* */
+ /* <Abstract> */
+ /* How client applications should allocate FreeType data structures. */
+ /* */
+ /* <Description> */
+ /* FreeType assumes that structures allocated by the user and passed */
+ /* as arguments are zeroed out except for the actual data. In other */
+ /* words, it is recommended to use `calloc' (or variants of it) */
+ /* instead of `malloc' for allocation. */
+ /* */
+ /*************************************************************************/
+
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /* */
+ /* B A S I C T Y P E S */
+ /* */
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* base_interface */
+ /* */
+ /* <Title> */
+ /* Base Interface */
+ /* */
+ /* <Abstract> */
+ /* The FreeType~2 base font interface. */
+ /* */
+ /* <Description> */
+ /* This section describes the public high-level API of FreeType~2. */
+ /* */
+ /* <Order> */
+ /* FT_Library */
+ /* FT_Face */
+ /* FT_Size */
+ /* FT_GlyphSlot */
+ /* FT_CharMap */
+ /* FT_Encoding */
+ /* */
+ /* FT_FaceRec */
+ /* */
+ /* FT_FACE_FLAG_SCALABLE */
+ /* FT_FACE_FLAG_FIXED_SIZES */
+ /* FT_FACE_FLAG_FIXED_WIDTH */
+ /* FT_FACE_FLAG_HORIZONTAL */
+ /* FT_FACE_FLAG_VERTICAL */
+ /* FT_FACE_FLAG_SFNT */
+ /* FT_FACE_FLAG_KERNING */
+ /* FT_FACE_FLAG_MULTIPLE_MASTERS */
+ /* FT_FACE_FLAG_GLYPH_NAMES */
+ /* FT_FACE_FLAG_EXTERNAL_STREAM */
+ /* FT_FACE_FLAG_FAST_GLYPHS */
+ /* FT_FACE_FLAG_HINTER */
+ /* */
+ /* FT_STYLE_FLAG_BOLD */
+ /* FT_STYLE_FLAG_ITALIC */
+ /* */
+ /* FT_SizeRec */
+ /* FT_Size_Metrics */
+ /* */
+ /* FT_GlyphSlotRec */
+ /* FT_Glyph_Metrics */
+ /* FT_SubGlyph */
+ /* */
+ /* FT_Bitmap_Size */
+ /* */
+ /* FT_Init_FreeType */
+ /* FT_Done_FreeType */
+ /* */
+ /* FT_New_Face */
+ /* FT_Done_Face */
+ /* FT_New_Memory_Face */
+ /* FT_Open_Face */
+ /* FT_Open_Args */
+ /* FT_Parameter */
+ /* FT_Attach_File */
+ /* FT_Attach_Stream */
+ /* */
+ /* FT_Set_Char_Size */
+ /* FT_Set_Pixel_Sizes */
+ /* FT_Request_Size */
+ /* FT_Select_Size */
+ /* FT_Size_Request_Type */
+ /* FT_Size_Request */
+ /* FT_Set_Transform */
+ /* FT_Load_Glyph */
+ /* FT_Get_Char_Index */
+ /* FT_Get_Name_Index */
+ /* FT_Load_Char */
+ /* */
+ /* FT_OPEN_MEMORY */
+ /* FT_OPEN_STREAM */
+ /* FT_OPEN_PATHNAME */
+ /* FT_OPEN_DRIVER */
+ /* FT_OPEN_PARAMS */
+ /* */
+ /* FT_LOAD_DEFAULT */
+ /* FT_LOAD_RENDER */
+ /* FT_LOAD_MONOCHROME */
+ /* FT_LOAD_LINEAR_DESIGN */
+ /* FT_LOAD_NO_SCALE */
+ /* FT_LOAD_NO_HINTING */
+ /* FT_LOAD_NO_BITMAP */
+ /* FT_LOAD_CROP_BITMAP */
+ /* */
+ /* FT_LOAD_VERTICAL_LAYOUT */
+ /* FT_LOAD_IGNORE_TRANSFORM */
+ /* FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */
+ /* FT_LOAD_FORCE_AUTOHINT */
+ /* FT_LOAD_NO_RECURSE */
+ /* FT_LOAD_PEDANTIC */
+ /* */
+ /* FT_LOAD_TARGET_NORMAL */
+ /* FT_LOAD_TARGET_LIGHT */
+ /* FT_LOAD_TARGET_MONO */
+ /* FT_LOAD_TARGET_LCD */
+ /* FT_LOAD_TARGET_LCD_V */
+ /* */
+ /* FT_Render_Glyph */
+ /* FT_Render_Mode */
+ /* FT_Get_Kerning */
+ /* FT_Kerning_Mode */
+ /* FT_Get_Track_Kerning */
+ /* FT_Get_Glyph_Name */
+ /* FT_Get_Postscript_Name */
+ /* */
+ /* FT_CharMapRec */
+ /* FT_Select_Charmap */
+ /* FT_Set_Charmap */
+ /* FT_Get_Charmap_Index */
+ /* */
+ /* FT_FSTYPE_INSTALLABLE_EMBEDDING */
+ /* FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING */
+ /* FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING */
+ /* FT_FSTYPE_EDITABLE_EMBEDDING */
+ /* FT_FSTYPE_NO_SUBSETTING */
+ /* FT_FSTYPE_BITMAP_EMBEDDING_ONLY */
+ /* */
+ /* FT_Get_FSType_Flags */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Glyph_Metrics */
+ /* */
+ /* <Description> */
+ /* A structure used to model the metrics of a single glyph. The */
+ /* values are expressed in 26.6 fractional pixel format; if the flag */
+ /* @FT_LOAD_NO_SCALE has been used while loading the glyph, values */
+ /* are expressed in font units instead. */
+ /* */
+ /* <Fields> */
+ /* width :: */
+ /* The glyph's width. */
+ /* */
+ /* height :: */
+ /* The glyph's height. */
+ /* */
+ /* horiBearingX :: */
+ /* Left side bearing for horizontal layout. */
+ /* */
+ /* horiBearingY :: */
+ /* Top side bearing for horizontal layout. */
+ /* */
+ /* horiAdvance :: */
+ /* Advance width for horizontal layout. */
+ /* */
+ /* vertBearingX :: */
+ /* Left side bearing for vertical layout. */
+ /* */
+ /* vertBearingY :: */
+ /* Top side bearing for vertical layout. */
+ /* */
+ /* vertAdvance :: */
+ /* Advance height for vertical layout. */
+ /* */
+ typedef struct FT_Glyph_Metrics_
+ {
+ FT_Pos width;
+ FT_Pos height;
+
+ FT_Pos horiBearingX;
+ FT_Pos horiBearingY;
+ FT_Pos horiAdvance;
+
+ FT_Pos vertBearingX;
+ FT_Pos vertBearingY;
+ FT_Pos vertAdvance;
+
+ } FT_Glyph_Metrics;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Bitmap_Size */
+ /* */
+ /* <Description> */
+ /* This structure models the metrics of a bitmap strike (i.e., a set */
+ /* of glyphs for a given point size and resolution) in a bitmap font. */
+ /* It is used for the `available_sizes' field of @FT_Face. */
+ /* */
+ /* <Fields> */
+ /* height :: The vertical distance, in pixels, between two */
+ /* consecutive baselines. It is always positive. */
+ /* */
+ /* width :: The average width, in pixels, of all glyphs in the */
+ /* strike. */
+ /* */
+ /* size :: The nominal size of the strike in 26.6 fractional */
+ /* points. This field is not very useful. */
+ /* */
+ /* x_ppem :: The horizontal ppem (nominal width) in 26.6 fractional */
+ /* pixels. */
+ /* */
+ /* y_ppem :: The vertical ppem (nominal height) in 26.6 fractional */
+ /* pixels. */
+ /* */
+ /* <Note> */
+ /* Windows FNT: */
+ /* The nominal size given in a FNT font is not reliable. Thus when */
+ /* the driver finds it incorrect, it sets `size' to some calculated */
+ /* values and sets `x_ppem' and `y_ppem' to the pixel width and */
+ /* height given in the font, respectively. */
+ /* */
+ /* TrueType embedded bitmaps: */
+ /* `size', `width', and `height' values are not contained in the */
+ /* bitmap strike itself. They are computed from the global font */
+ /* parameters. */
+ /* */
+ typedef struct FT_Bitmap_Size_
+ {
+ FT_Short height;
+ FT_Short width;
+
+ FT_Pos size;
+
+ FT_Pos x_ppem;
+ FT_Pos y_ppem;
+
+ } FT_Bitmap_Size;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /* */
+ /* O B J E C T C L A S S E S */
+ /* */
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Library */
+ /* */
+ /* <Description> */
+ /* A handle to a FreeType library instance. Each `library' is */
+ /* completely independent from the others; it is the `root' of a set */
+ /* of objects like fonts, faces, sizes, etc. */
+ /* */
+ /* It also embeds a memory manager (see @FT_Memory), as well as a */
+ /* scan-line converter object (see @FT_Raster). */
+ /* */
+ /* For multi-threading applications each thread should have its own */
+ /* FT_Library object. */
+ /* */
+ /* <Note> */
+ /* Library objects are normally created by @FT_Init_FreeType, and */
+ /* destroyed with @FT_Done_FreeType. */
+ /* */
+ typedef struct FT_LibraryRec_ *FT_Library;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Module */
+ /* */
+ /* <Description> */
+ /* A handle to a given FreeType module object. Each module can be a */
+ /* font driver, a renderer, or anything else that provides services */
+ /* to the formers. */
+ /* */
+ typedef struct FT_ModuleRec_* FT_Module;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Driver */
+ /* */
+ /* <Description> */
+ /* A handle to a given FreeType font driver object. Each font driver */
+ /* is a special module capable of creating faces from font files. */
+ /* */
+ typedef struct FT_DriverRec_* FT_Driver;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Renderer */
+ /* */
+ /* <Description> */
+ /* A handle to a given FreeType renderer. A renderer is a special */
+ /* module in charge of converting a glyph image to a bitmap, when */
+ /* necessary. Each renderer supports a given glyph image format, and */
+ /* one or more target surface depths. */
+ /* */
+ typedef struct FT_RendererRec_* FT_Renderer;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Face */
+ /* */
+ /* <Description> */
+ /* A handle to a given typographic face object. A face object models */
+ /* a given typeface, in a given style. */
+ /* */
+ /* <Note> */
+ /* Each face object also owns a single @FT_GlyphSlot object, as well */
+ /* as one or more @FT_Size objects. */
+ /* */
+ /* Use @FT_New_Face or @FT_Open_Face to create a new face object from */
+ /* a given filepathname or a custom input stream. */
+ /* */
+ /* Use @FT_Done_Face to destroy it (along with its slot and sizes). */
+ /* */
+ /* <Also> */
+ /* See @FT_FaceRec for the publicly accessible fields of a given face */
+ /* object. */
+ /* */
+ typedef struct FT_FaceRec_* FT_Face;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Size */
+ /* */
+ /* <Description> */
+ /* A handle to an object used to model a face scaled to a given */
+ /* character size. */
+ /* */
+ /* <Note> */
+ /* Each @FT_Face has an _active_ @FT_Size object that is used by */
+ /* functions like @FT_Load_Glyph to determine the scaling */
+ /* transformation which is used to load and hint glyphs and metrics. */
+ /* */
+ /* You can use @FT_Set_Char_Size, @FT_Set_Pixel_Sizes, */
+ /* @FT_Request_Size or even @FT_Select_Size to change the content */
+ /* (i.e., the scaling values) of the active @FT_Size. */
+ /* */
+ /* You can use @FT_New_Size to create additional size objects for a */
+ /* given @FT_Face, but they won't be used by other functions until */
+ /* you activate it through @FT_Activate_Size. Only one size can be */
+ /* activated at any given time per face. */
+ /* */
+ /* <Also> */
+ /* See @FT_SizeRec for the publicly accessible fields of a given size */
+ /* object. */
+ /* */
+ typedef struct FT_SizeRec_* FT_Size;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_GlyphSlot */
+ /* */
+ /* <Description> */
+ /* A handle to a given `glyph slot'. A slot is a container where it */
+ /* is possible to load any of the glyphs contained in its parent */
+ /* face. */
+ /* */
+ /* In other words, each time you call @FT_Load_Glyph or */
+ /* @FT_Load_Char, the slot's content is erased by the new glyph data, */
+ /* i.e., the glyph's metrics, its image (bitmap or outline), and */
+ /* other control information. */
+ /* */
+ /* <Also> */
+ /* See @FT_GlyphSlotRec for the publicly accessible glyph fields. */
+ /* */
+ typedef struct FT_GlyphSlotRec_* FT_GlyphSlot;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_CharMap */
+ /* */
+ /* <Description> */
+ /* A handle to a given character map. A charmap is used to translate */
+ /* character codes in a given encoding into glyph indexes for its */
+ /* parent's face. Some font formats may provide several charmaps per */
+ /* font. */
+ /* */
+ /* Each face object owns zero or more charmaps, but only one of them */
+ /* can be `active' and used by @FT_Get_Char_Index or @FT_Load_Char. */
+ /* */
+ /* The list of available charmaps in a face is available through the */
+ /* `face->num_charmaps' and `face->charmaps' fields of @FT_FaceRec. */
+ /* */
+ /* The currently active charmap is available as `face->charmap'. */
+ /* You should call @FT_Set_Charmap to change it. */
+ /* */
+ /* <Note> */
+ /* When a new face is created (either through @FT_New_Face or */
+ /* @FT_Open_Face), the library looks for a Unicode charmap within */
+ /* the list and automatically activates it. */
+ /* */
+ /* <Also> */
+ /* See @FT_CharMapRec for the publicly accessible fields of a given */
+ /* character map. */
+ /* */
+ typedef struct FT_CharMapRec_* FT_CharMap;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Macro> */
+ /* FT_ENC_TAG */
+ /* */
+ /* <Description> */
+ /* This macro converts four-letter tags into an unsigned long. It is */
+ /* used to define `encoding' identifiers (see @FT_Encoding). */
+ /* */
+ /* <Note> */
+ /* Since many 16-bit compilers don't like 32-bit enumerations, you */
+ /* should redefine this macro in case of problems to something like */
+ /* this: */
+ /* */
+ /* { */
+ /* #define FT_ENC_TAG( value, a, b, c, d ) value */
+ /* } */
+ /* */
+ /* to get a simple enumeration without assigning special numbers. */
+ /* */
+
+#ifndef FT_ENC_TAG
+#define FT_ENC_TAG( value, a, b, c, d ) \
+ value = ( ( (FT_UInt32)(a) << 24 ) | \
+ ( (FT_UInt32)(b) << 16 ) | \
+ ( (FT_UInt32)(c) << 8 ) | \
+ (FT_UInt32)(d) )
+
+#endif /* FT_ENC_TAG */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Encoding */
+ /* */
+ /* <Description> */
+ /* An enumeration used to specify character sets supported by */
+ /* charmaps. Used in the @FT_Select_Charmap API function. */
+ /* */
+ /* <Note> */
+ /* Despite the name, this enumeration lists specific character */
+ /* repertories (i.e., charsets), and not text encoding methods (e.g., */
+ /* UTF-8, UTF-16, GB2312_EUC, etc.). */
+ /* */
+ /* Because of 32-bit charcodes defined in Unicode (i.e., surrogates), */
+ /* all character codes must be expressed as FT_Longs. */
+ /* */
+ /* Other encodings might be defined in the future. */
+ /* */
+ /* <Values> */
+ /* FT_ENCODING_NONE :: */
+ /* The encoding value~0 is reserved. */
+ /* */
+ /* FT_ENCODING_UNICODE :: */
+ /* Corresponds to the Unicode character set. This value covers */
+ /* all versions of the Unicode repertoire, including ASCII and */
+ /* Latin-1. Most fonts include a Unicode charmap, but not all */
+ /* of them. */
+ /* */
+ /* FT_ENCODING_MS_SYMBOL :: */
+ /* Corresponds to the Microsoft Symbol encoding, used to encode */
+ /* mathematical symbols in the 32..255 character code range. For */
+ /* more information, see `http://www.ceviz.net/symbol.htm'. */
+ /* */
+ /* FT_ENCODING_SJIS :: */
+ /* Corresponds to Japanese SJIS encoding. More info at */
+ /* at `http://langsupport.japanreference.com/encoding.shtml'. */
+ /* See note on multi-byte encodings below. */
+ /* */
+ /* FT_ENCODING_GB2312 :: */
+ /* Corresponds to an encoding system for Simplified Chinese as used */
+ /* used in mainland China. */
+ /* */
+ /* FT_ENCODING_BIG5 :: */
+ /* Corresponds to an encoding system for Traditional Chinese as */
+ /* used in Taiwan and Hong Kong. */
+ /* */
+ /* FT_ENCODING_WANSUNG :: */
+ /* Corresponds to the Korean encoding system known as Wansung. */
+ /* For more information see */
+ /* `http://www.microsoft.com/typography/unicode/949.txt'. */
+ /* */
+ /* FT_ENCODING_JOHAB :: */
+ /* The Korean standard character set (KS~C 5601-1992), which */
+ /* corresponds to MS Windows code page 1361. This character set */
+ /* includes all possible Hangeul character combinations. */
+ /* */
+ /* FT_ENCODING_ADOBE_LATIN_1 :: */
+ /* Corresponds to a Latin-1 encoding as defined in a Type~1 */
+ /* PostScript font. It is limited to 256 character codes. */
+ /* */
+ /* FT_ENCODING_ADOBE_STANDARD :: */
+ /* Corresponds to the Adobe Standard encoding, as found in Type~1, */
+ /* CFF, and OpenType/CFF fonts. It is limited to 256 character */
+ /* codes. */
+ /* */
+ /* FT_ENCODING_ADOBE_EXPERT :: */
+ /* Corresponds to the Adobe Expert encoding, as found in Type~1, */
+ /* CFF, and OpenType/CFF fonts. It is limited to 256 character */
+ /* codes. */
+ /* */
+ /* FT_ENCODING_ADOBE_CUSTOM :: */
+ /* Corresponds to a custom encoding, as found in Type~1, CFF, and */
+ /* OpenType/CFF fonts. It is limited to 256 character codes. */
+ /* */
+ /* FT_ENCODING_APPLE_ROMAN :: */
+ /* Corresponds to the 8-bit Apple roman encoding. Many TrueType */
+ /* and OpenType fonts contain a charmap for this encoding, since */
+ /* older versions of Mac OS are able to use it. */
+ /* */
+ /* FT_ENCODING_OLD_LATIN_2 :: */
+ /* This value is deprecated and was never used nor reported by */
+ /* FreeType. Don't use or test for it. */
+ /* */
+ /* FT_ENCODING_MS_SJIS :: */
+ /* Same as FT_ENCODING_SJIS. Deprecated. */
+ /* */
+ /* FT_ENCODING_MS_GB2312 :: */
+ /* Same as FT_ENCODING_GB2312. Deprecated. */
+ /* */
+ /* FT_ENCODING_MS_BIG5 :: */
+ /* Same as FT_ENCODING_BIG5. Deprecated. */
+ /* */
+ /* FT_ENCODING_MS_WANSUNG :: */
+ /* Same as FT_ENCODING_WANSUNG. Deprecated. */
+ /* */
+ /* FT_ENCODING_MS_JOHAB :: */
+ /* Same as FT_ENCODING_JOHAB. Deprecated. */
+ /* */
+ /* <Note> */
+ /* By default, FreeType automatically synthesizes a Unicode charmap */
+ /* for PostScript fonts, using their glyph names dictionaries. */
+ /* However, it also reports the encodings defined explicitly in the */
+ /* font file, for the cases when they are needed, with the Adobe */
+ /* values as well. */
+ /* */
+ /* FT_ENCODING_NONE is set by the BDF and PCF drivers if the charmap */
+ /* is neither Unicode nor ISO-8859-1 (otherwise it is set to */
+ /* FT_ENCODING_UNICODE). Use @FT_Get_BDF_Charset_ID to find out */
+ /* which encoding is really present. If, for example, the */
+ /* `cs_registry' field is `KOI8' and the `cs_encoding' field is `R', */
+ /* the font is encoded in KOI8-R. */
+ /* */
+ /* FT_ENCODING_NONE is always set (with a single exception) by the */
+ /* winfonts driver. Use @FT_Get_WinFNT_Header and examine the */
+ /* `charset' field of the @FT_WinFNT_HeaderRec structure to find out */
+ /* which encoding is really present. For example, */
+ /* @FT_WinFNT_ID_CP1251 (204) means Windows code page 1251 (for */
+ /* Russian). */
+ /* */
+ /* FT_ENCODING_NONE is set if `platform_id' is @TT_PLATFORM_MACINTOSH */
+ /* and `encoding_id' is not @TT_MAC_ID_ROMAN (otherwise it is set to */
+ /* FT_ENCODING_APPLE_ROMAN). */
+ /* */
+ /* If `platform_id' is @TT_PLATFORM_MACINTOSH, use the function */
+ /* @FT_Get_CMap_Language_ID to query the Mac language ID which may */
+ /* be needed to be able to distinguish Apple encoding variants. See */
+ /* */
+ /* http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/README.TXT */
+ /* */
+ /* to get an idea how to do that. Basically, if the language ID */
+ /* is~0, don't use it, otherwise subtract 1 from the language ID. */
+ /* Then examine `encoding_id'. If, for example, `encoding_id' is */
+ /* @TT_MAC_ID_ROMAN and the language ID (minus~1) is */
+ /* `TT_MAC_LANGID_GREEK', it is the Greek encoding, not Roman. */
+ /* @TT_MAC_ID_ARABIC with `TT_MAC_LANGID_FARSI' means the Farsi */
+ /* variant the Arabic encoding. */
+ /* */
+ typedef enum FT_Encoding_
+ {
+ FT_ENC_TAG( FT_ENCODING_NONE, 0, 0, 0, 0 ),
+
+ FT_ENC_TAG( FT_ENCODING_MS_SYMBOL, 's', 'y', 'm', 'b' ),
+ FT_ENC_TAG( FT_ENCODING_UNICODE, 'u', 'n', 'i', 'c' ),
+
+ FT_ENC_TAG( FT_ENCODING_SJIS, 's', 'j', 'i', 's' ),
+ FT_ENC_TAG( FT_ENCODING_GB2312, 'g', 'b', ' ', ' ' ),
+ FT_ENC_TAG( FT_ENCODING_BIG5, 'b', 'i', 'g', '5' ),
+ FT_ENC_TAG( FT_ENCODING_WANSUNG, 'w', 'a', 'n', 's' ),
+ FT_ENC_TAG( FT_ENCODING_JOHAB, 'j', 'o', 'h', 'a' ),
+
+ /* for backwards compatibility */
+ FT_ENCODING_MS_SJIS = FT_ENCODING_SJIS,
+ FT_ENCODING_MS_GB2312 = FT_ENCODING_GB2312,
+ FT_ENCODING_MS_BIG5 = FT_ENCODING_BIG5,
+ FT_ENCODING_MS_WANSUNG = FT_ENCODING_WANSUNG,
+ FT_ENCODING_MS_JOHAB = FT_ENCODING_JOHAB,
+
+ FT_ENC_TAG( FT_ENCODING_ADOBE_STANDARD, 'A', 'D', 'O', 'B' ),
+ FT_ENC_TAG( FT_ENCODING_ADOBE_EXPERT, 'A', 'D', 'B', 'E' ),
+ FT_ENC_TAG( FT_ENCODING_ADOBE_CUSTOM, 'A', 'D', 'B', 'C' ),
+ FT_ENC_TAG( FT_ENCODING_ADOBE_LATIN_1, 'l', 'a', 't', '1' ),
+
+ FT_ENC_TAG( FT_ENCODING_OLD_LATIN_2, 'l', 'a', 't', '2' ),
+
+ FT_ENC_TAG( FT_ENCODING_APPLE_ROMAN, 'a', 'r', 'm', 'n' )
+
+ } FT_Encoding;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* ft_encoding_xxx */
+ /* */
+ /* <Description> */
+ /* These constants are deprecated; use the corresponding @FT_Encoding */
+ /* values instead. */
+ /* */
+#define ft_encoding_none FT_ENCODING_NONE
+#define ft_encoding_unicode FT_ENCODING_UNICODE
+#define ft_encoding_symbol FT_ENCODING_MS_SYMBOL
+#define ft_encoding_latin_1 FT_ENCODING_ADOBE_LATIN_1
+#define ft_encoding_latin_2 FT_ENCODING_OLD_LATIN_2
+#define ft_encoding_sjis FT_ENCODING_SJIS
+#define ft_encoding_gb2312 FT_ENCODING_GB2312
+#define ft_encoding_big5 FT_ENCODING_BIG5
+#define ft_encoding_wansung FT_ENCODING_WANSUNG
+#define ft_encoding_johab FT_ENCODING_JOHAB
+
+#define ft_encoding_adobe_standard FT_ENCODING_ADOBE_STANDARD
+#define ft_encoding_adobe_expert FT_ENCODING_ADOBE_EXPERT
+#define ft_encoding_adobe_custom FT_ENCODING_ADOBE_CUSTOM
+#define ft_encoding_apple_roman FT_ENCODING_APPLE_ROMAN
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_CharMapRec */
+ /* */
+ /* <Description> */
+ /* The base charmap structure. */
+ /* */
+ /* <Fields> */
+ /* face :: A handle to the parent face object. */
+ /* */
+ /* encoding :: An @FT_Encoding tag identifying the charmap. Use */
+ /* this with @FT_Select_Charmap. */
+ /* */
+ /* platform_id :: An ID number describing the platform for the */
+ /* following encoding ID. This comes directly from */
+ /* the TrueType specification and should be emulated */
+ /* for other formats. */
+ /* */
+ /* encoding_id :: A platform specific encoding number. This also */
+ /* comes from the TrueType specification and should be */
+ /* emulated similarly. */
+ /* */
+ typedef struct FT_CharMapRec_
+ {
+ FT_Face face;
+ FT_Encoding encoding;
+ FT_UShort platform_id;
+ FT_UShort encoding_id;
+
+ } FT_CharMapRec;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /* */
+ /* B A S E O B J E C T C L A S S E S */
+ /* */
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Face_Internal */
+ /* */
+ /* <Description> */
+ /* An opaque handle to an `FT_Face_InternalRec' structure, used to */
+ /* model private data of a given @FT_Face object. */
+ /* */
+ /* This structure might change between releases of FreeType~2 and is */
+ /* not generally available to client applications. */
+ /* */
+ typedef struct FT_Face_InternalRec_* FT_Face_Internal;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_FaceRec */
+ /* */
+ /* <Description> */
+ /* FreeType root face class structure. A face object models a */
+ /* typeface in a font file. */
+ /* */
+ /* <Fields> */
+ /* num_faces :: The number of faces in the font file. Some */
+ /* font formats can have multiple faces in */
+ /* a font file. */
+ /* */
+ /* face_index :: The index of the face in the font file. It */
+ /* is set to~0 if there is only one face in */
+ /* the font file. */
+ /* */
+ /* face_flags :: A set of bit flags that give important */
+ /* information about the face; see */
+ /* @FT_FACE_FLAG_XXX for the details. */
+ /* */
+ /* style_flags :: A set of bit flags indicating the style of */
+ /* the face; see @FT_STYLE_FLAG_XXX for the */
+ /* details. */
+ /* */
+ /* num_glyphs :: The number of glyphs in the face. If the */
+ /* face is scalable and has sbits (see */
+ /* `num_fixed_sizes'), it is set to the number */
+ /* of outline glyphs. */
+ /* */
+ /* For CID-keyed fonts, this value gives the */
+ /* highest CID used in the font. */
+ /* */
+ /* family_name :: The face's family name. This is an ASCII */
+ /* string, usually in English, which describes */
+ /* the typeface's family (like `Times New */
+ /* Roman', `Bodoni', `Garamond', etc). This */
+ /* is a least common denominator used to list */
+ /* fonts. Some formats (TrueType & OpenType) */
+ /* provide localized and Unicode versions of */
+ /* this string. Applications should use the */
+ /* format specific interface to access them. */
+ /* Can be NULL (e.g., in fonts embedded in a */
+ /* PDF file). */
+ /* */
+ /* style_name :: The face's style name. This is an ASCII */
+ /* string, usually in English, which describes */
+ /* the typeface's style (like `Italic', */
+ /* `Bold', `Condensed', etc). Not all font */
+ /* formats provide a style name, so this field */
+ /* is optional, and can be set to NULL. As */
+ /* for `family_name', some formats provide */
+ /* localized and Unicode versions of this */
+ /* string. Applications should use the format */
+ /* specific interface to access them. */
+ /* */
+ /* num_fixed_sizes :: The number of bitmap strikes in the face. */
+ /* Even if the face is scalable, there might */
+ /* still be bitmap strikes, which are called */
+ /* `sbits' in that case. */
+ /* */
+ /* available_sizes :: An array of @FT_Bitmap_Size for all bitmap */
+ /* strikes in the face. It is set to NULL if */
+ /* there is no bitmap strike. */
+ /* */
+ /* num_charmaps :: The number of charmaps in the face. */
+ /* */
+ /* charmaps :: An array of the charmaps of the face. */
+ /* */
+ /* generic :: A field reserved for client uses. See the */
+ /* @FT_Generic type description. */
+ /* */
+ /* bbox :: The font bounding box. Coordinates are */
+ /* expressed in font units (see */
+ /* `units_per_EM'). The box is large enough */
+ /* to contain any glyph from the font. Thus, */
+ /* `bbox.yMax' can be seen as the `maximal */
+ /* ascender', and `bbox.yMin' as the `minimal */
+ /* descender'. Only relevant for scalable */
+ /* formats. */
+ /* */
+ /* Note that the bounding box might be off by */
+ /* (at least) one pixel for hinted fonts. See */
+ /* @FT_Size_Metrics for further discussion. */
+ /* */
+ /* units_per_EM :: The number of font units per EM square for */
+ /* this face. This is typically 2048 for */
+ /* TrueType fonts, and 1000 for Type~1 fonts. */
+ /* Only relevant for scalable formats. */
+ /* */
+ /* ascender :: The typographic ascender of the face, */
+ /* expressed in font units. For font formats */
+ /* not having this information, it is set to */
+ /* `bbox.yMax'. Only relevant for scalable */
+ /* formats. */
+ /* */
+ /* descender :: The typographic descender of the face, */
+ /* expressed in font units. For font formats */
+ /* not having this information, it is set to */
+ /* `bbox.yMin'. Note that this field is */
+ /* usually negative. Only relevant for */
+ /* scalable formats. */
+ /* */
+ /* height :: The height is the vertical distance */
+ /* between two consecutive baselines, */
+ /* expressed in font units. It is always */
+ /* positive. Only relevant for scalable */
+ /* formats. */
+ /* */
+ /* max_advance_width :: The maximal advance width, in font units, */
+ /* for all glyphs in this face. This can be */
+ /* used to make word wrapping computations */
+ /* faster. Only relevant for scalable */
+ /* formats. */
+ /* */
+ /* max_advance_height :: The maximal advance height, in font units, */
+ /* for all glyphs in this face. This is only */
+ /* relevant for vertical layouts, and is set */
+ /* to `height' for fonts that do not provide */
+ /* vertical metrics. Only relevant for */
+ /* scalable formats. */
+ /* */
+ /* underline_position :: The position, in font units, of the */
+ /* underline line for this face. It is the */
+ /* center of the underlining stem. Only */
+ /* relevant for scalable formats. */
+ /* */
+ /* underline_thickness :: The thickness, in font units, of the */
+ /* underline for this face. Only relevant for */
+ /* scalable formats. */
+ /* */
+ /* glyph :: The face's associated glyph slot(s). */
+ /* */
+ /* size :: The current active size for this face. */
+ /* */
+ /* charmap :: The current active charmap for this face. */
+ /* */
+ /* <Note> */
+ /* Fields may be changed after a call to @FT_Attach_File or */
+ /* @FT_Attach_Stream. */
+ /* */
+ typedef struct FT_FaceRec_
+ {
+ FT_Long num_faces;
+ FT_Long face_index;
+
+ FT_Long face_flags;
+ FT_Long style_flags;
+
+ FT_Long num_glyphs;
+
+ FT_String* family_name;
+ FT_String* style_name;
+
+ FT_Int num_fixed_sizes;
+ FT_Bitmap_Size* available_sizes;
+
+ FT_Int num_charmaps;
+ FT_CharMap* charmaps;
+
+ FT_Generic generic;
+
+ /*# The following member variables (down to `underline_thickness') */
+ /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size */
+ /*# for bitmap fonts. */
+ FT_BBox bbox;
+
+ FT_UShort units_per_EM;
+ FT_Short ascender;
+ FT_Short descender;
+ FT_Short height;
+
+ FT_Short max_advance_width;
+ FT_Short max_advance_height;
+
+ FT_Short underline_position;
+ FT_Short underline_thickness;
+
+ FT_GlyphSlot glyph;
+ FT_Size size;
+ FT_CharMap charmap;
+
+ /*@private begin */
+
+ FT_Driver driver;
+ FT_Memory memory;
+ FT_Stream stream;
+
+ FT_ListRec sizes_list;
+
+ FT_Generic autohint;
+ void* extensions;
+
+ FT_Face_Internal internal;
+
+ /*@private end */
+
+ } FT_FaceRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_FACE_FLAG_XXX */
+ /* */
+ /* <Description> */
+ /* A list of bit flags used in the `face_flags' field of the */
+ /* @FT_FaceRec structure. They inform client applications of */
+ /* properties of the corresponding face. */
+ /* */
+ /* <Values> */
+ /* FT_FACE_FLAG_SCALABLE :: */
+ /* Indicates that the face contains outline glyphs. This doesn't */
+ /* prevent bitmap strikes, i.e., a face can have both this and */
+ /* and @FT_FACE_FLAG_FIXED_SIZES set. */
+ /* */
+ /* FT_FACE_FLAG_FIXED_SIZES :: */
+ /* Indicates that the face contains bitmap strikes. See also the */
+ /* `num_fixed_sizes' and `available_sizes' fields of @FT_FaceRec. */
+ /* */
+ /* FT_FACE_FLAG_FIXED_WIDTH :: */
+ /* Indicates that the face contains fixed-width characters (like */
+ /* Courier, Lucido, MonoType, etc.). */
+ /* */
+ /* FT_FACE_FLAG_SFNT :: */
+ /* Indicates that the face uses the `sfnt' storage scheme. For */
+ /* now, this means TrueType and OpenType. */
+ /* */
+ /* FT_FACE_FLAG_HORIZONTAL :: */
+ /* Indicates that the face contains horizontal glyph metrics. This */
+ /* should be set for all common formats. */
+ /* */
+ /* FT_FACE_FLAG_VERTICAL :: */
+ /* Indicates that the face contains vertical glyph metrics. This */
+ /* is only available in some formats, not all of them. */
+ /* */
+ /* FT_FACE_FLAG_KERNING :: */
+ /* Indicates that the face contains kerning information. If set, */
+ /* the kerning distance can be retrieved through the function */
+ /* @FT_Get_Kerning. Otherwise the function always return the */
+ /* vector (0,0). Note that FreeType doesn't handle kerning data */
+ /* from the `GPOS' table (as present in some OpenType fonts). */
+ /* */
+ /* FT_FACE_FLAG_FAST_GLYPHS :: */
+ /* THIS FLAG IS DEPRECATED. DO NOT USE OR TEST IT. */
+ /* */
+ /* FT_FACE_FLAG_MULTIPLE_MASTERS :: */
+ /* Indicates that the font contains multiple masters and is capable */
+ /* of interpolating between them. See the multiple-masters */
+ /* specific API for details. */
+ /* */
+ /* FT_FACE_FLAG_GLYPH_NAMES :: */
+ /* Indicates that the font contains glyph names that can be */
+ /* retrieved through @FT_Get_Glyph_Name. Note that some TrueType */
+ /* fonts contain broken glyph name tables. Use the function */
+ /* @FT_Has_PS_Glyph_Names when needed. */
+ /* */
+ /* FT_FACE_FLAG_EXTERNAL_STREAM :: */
+ /* Used internally by FreeType to indicate that a face's stream was */
+ /* provided by the client application and should not be destroyed */
+ /* when @FT_Done_Face is called. Don't read or test this flag. */
+ /* */
+ /* FT_FACE_FLAG_HINTER :: */
+ /* Set if the font driver has a hinting machine of its own. For */
+ /* example, with TrueType fonts, it makes sense to use data from */
+ /* the SFNT `gasp' table only if the native TrueType hinting engine */
+ /* (with the bytecode interpreter) is available and active. */
+ /* */
+ /* FT_FACE_FLAG_CID_KEYED :: */
+ /* Set if the font is CID-keyed. In that case, the font is not */
+ /* accessed by glyph indices but by CID values. For subsetted */
+ /* CID-keyed fonts this has the consequence that not all index */
+ /* values are a valid argument to FT_Load_Glyph. Only the CID */
+ /* values for which corresponding glyphs in the subsetted font */
+ /* exist make FT_Load_Glyph return successfully; in all other cases */
+ /* you get an `FT_Err_Invalid_Argument' error. */
+ /* */
+ /* Note that CID-keyed fonts which are in an SFNT wrapper don't */
+ /* have this flag set since the glyphs are accessed in the normal */
+ /* way (using contiguous indices); the `CID-ness' isn't visible to */
+ /* the application. */
+ /* */
+ /* FT_FACE_FLAG_TRICKY :: */
+ /* Set if the font is `tricky', this is, it always needs the */
+ /* font format's native hinting engine to get a reasonable result. */
+ /* A typical example is the Chinese font `mingli.ttf' which uses */
+ /* TrueType bytecode instructions to move and scale all of its */
+ /* subglyphs. */
+ /* */
+ /* It is not possible to autohint such fonts using */
+ /* @FT_LOAD_FORCE_AUTOHINT; it will also ignore */
+ /* @FT_LOAD_NO_HINTING. You have to set both FT_LOAD_NO_HINTING */
+ /* and @FT_LOAD_NO_AUTOHINT to really disable hinting; however, you */
+ /* probably never want this except for demonstration purposes. */
+ /* */
+ /* Currently, there are six TrueType fonts in the list of tricky */
+ /* fonts; they are hard-coded in file `ttobjs.c'. */
+ /* */
+#define FT_FACE_FLAG_SCALABLE ( 1L << 0 )
+#define FT_FACE_FLAG_FIXED_SIZES ( 1L << 1 )
+#define FT_FACE_FLAG_FIXED_WIDTH ( 1L << 2 )
+#define FT_FACE_FLAG_SFNT ( 1L << 3 )
+#define FT_FACE_FLAG_HORIZONTAL ( 1L << 4 )
+#define FT_FACE_FLAG_VERTICAL ( 1L << 5 )
+#define FT_FACE_FLAG_KERNING ( 1L << 6 )
+#define FT_FACE_FLAG_FAST_GLYPHS ( 1L << 7 )
+#define FT_FACE_FLAG_MULTIPLE_MASTERS ( 1L << 8 )
+#define FT_FACE_FLAG_GLYPH_NAMES ( 1L << 9 )
+#define FT_FACE_FLAG_EXTERNAL_STREAM ( 1L << 10 )
+#define FT_FACE_FLAG_HINTER ( 1L << 11 )
+#define FT_FACE_FLAG_CID_KEYED ( 1L << 12 )
+#define FT_FACE_FLAG_TRICKY ( 1L << 13 )
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_HAS_HORIZONTAL( face )
+ *
+ * @description:
+ * A macro that returns true whenever a face object contains
+ * horizontal metrics (this is true for all font formats though).
+ *
+ * @also:
+ * @FT_HAS_VERTICAL can be used to check for vertical metrics.
+ *
+ */
+#define FT_HAS_HORIZONTAL( face ) \
+ ( face->face_flags & FT_FACE_FLAG_HORIZONTAL )
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_HAS_VERTICAL( face )
+ *
+ * @description:
+ * A macro that returns true whenever a face object contains vertical
+ * metrics.
+ *
+ */
+#define FT_HAS_VERTICAL( face ) \
+ ( face->face_flags & FT_FACE_FLAG_VERTICAL )
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_HAS_KERNING( face )
+ *
+ * @description:
+ * A macro that returns true whenever a face object contains kerning
+ * data that can be accessed with @FT_Get_Kerning.
+ *
+ */
+#define FT_HAS_KERNING( face ) \
+ ( face->face_flags & FT_FACE_FLAG_KERNING )
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_IS_SCALABLE( face )
+ *
+ * @description:
+ * A macro that returns true whenever a face object contains a scalable
+ * font face (true for TrueType, Type~1, Type~42, CID, OpenType/CFF,
+ * and PFR font formats.
+ *
+ */
+#define FT_IS_SCALABLE( face ) \
+ ( face->face_flags & FT_FACE_FLAG_SCALABLE )
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_IS_SFNT( face )
+ *
+ * @description:
+ * A macro that returns true whenever a face object contains a font
+ * whose format is based on the SFNT storage scheme. This usually
+ * means: TrueType fonts, OpenType fonts, as well as SFNT-based embedded
+ * bitmap fonts.
+ *
+ * If this macro is true, all functions defined in @FT_SFNT_NAMES_H and
+ * @FT_TRUETYPE_TABLES_H are available.
+ *
+ */
+#define FT_IS_SFNT( face ) \
+ ( face->face_flags & FT_FACE_FLAG_SFNT )
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_IS_FIXED_WIDTH( face )
+ *
+ * @description:
+ * A macro that returns true whenever a face object contains a font face
+ * that contains fixed-width (or `monospace', `fixed-pitch', etc.)
+ * glyphs.
+ *
+ */
+#define FT_IS_FIXED_WIDTH( face ) \
+ ( face->face_flags & FT_FACE_FLAG_FIXED_WIDTH )
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_HAS_FIXED_SIZES( face )
+ *
+ * @description:
+ * A macro that returns true whenever a face object contains some
+ * embedded bitmaps. See the `available_sizes' field of the
+ * @FT_FaceRec structure.
+ *
+ */
+#define FT_HAS_FIXED_SIZES( face ) \
+ ( face->face_flags & FT_FACE_FLAG_FIXED_SIZES )
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_HAS_FAST_GLYPHS( face )
+ *
+ * @description:
+ * Deprecated.
+ *
+ */
+#define FT_HAS_FAST_GLYPHS( face ) 0
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_HAS_GLYPH_NAMES( face )
+ *
+ * @description:
+ * A macro that returns true whenever a face object contains some glyph
+ * names that can be accessed through @FT_Get_Glyph_Name.
+ *
+ */
+#define FT_HAS_GLYPH_NAMES( face ) \
+ ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES )
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_HAS_MULTIPLE_MASTERS( face )
+ *
+ * @description:
+ * A macro that returns true whenever a face object contains some
+ * multiple masters. The functions provided by @FT_MULTIPLE_MASTERS_H
+ * are then available to choose the exact design you want.
+ *
+ */
+#define FT_HAS_MULTIPLE_MASTERS( face ) \
+ ( face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS )
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_IS_CID_KEYED( face )
+ *
+ * @description:
+ * A macro that returns true whenever a face object contains a CID-keyed
+ * font. See the discussion of @FT_FACE_FLAG_CID_KEYED for more
+ * details.
+ *
+ * If this macro is true, all functions defined in @FT_CID_H are
+ * available.
+ *
+ */
+#define FT_IS_CID_KEYED( face ) \
+ ( face->face_flags & FT_FACE_FLAG_CID_KEYED )
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_IS_TRICKY( face )
+ *
+ * @description:
+ * A macro that returns true whenever a face represents a `tricky' font.
+ * See the discussion of @FT_FACE_FLAG_TRICKY for more details.
+ *
+ */
+#define FT_IS_TRICKY( face ) \
+ ( face->face_flags & FT_FACE_FLAG_TRICKY )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Const> */
+ /* FT_STYLE_FLAG_XXX */
+ /* */
+ /* <Description> */
+ /* A list of bit-flags used to indicate the style of a given face. */
+ /* These are used in the `style_flags' field of @FT_FaceRec. */
+ /* */
+ /* <Values> */
+ /* FT_STYLE_FLAG_ITALIC :: */
+ /* Indicates that a given face style is italic or oblique. */
+ /* */
+ /* FT_STYLE_FLAG_BOLD :: */
+ /* Indicates that a given face is bold. */
+ /* */
+ /* <Note> */
+ /* The style information as provided by FreeType is very basic. More */
+ /* details are beyond the scope and should be done on a higher level */
+ /* (for example, by analyzing various fields of the `OS/2' table in */
+ /* SFNT based fonts). */
+ /* */
+#define FT_STYLE_FLAG_ITALIC ( 1 << 0 )
+#define FT_STYLE_FLAG_BOLD ( 1 << 1 )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Size_Internal */
+ /* */
+ /* <Description> */
+ /* An opaque handle to an `FT_Size_InternalRec' structure, used to */
+ /* model private data of a given @FT_Size object. */
+ /* */
+ typedef struct FT_Size_InternalRec_* FT_Size_Internal;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Size_Metrics */
+ /* */
+ /* <Description> */
+ /* The size metrics structure gives the metrics of a size object. */
+ /* */
+ /* <Fields> */
+ /* x_ppem :: The width of the scaled EM square in pixels, hence */
+ /* the term `ppem' (pixels per EM). It is also */
+ /* referred to as `nominal width'. */
+ /* */
+ /* y_ppem :: The height of the scaled EM square in pixels, */
+ /* hence the term `ppem' (pixels per EM). It is also */
+ /* referred to as `nominal height'. */
+ /* */
+ /* x_scale :: A 16.16 fractional scaling value used to convert */
+ /* horizontal metrics from font units to 26.6 */
+ /* fractional pixels. Only relevant for scalable */
+ /* font formats. */
+ /* */
+ /* y_scale :: A 16.16 fractional scaling value used to convert */
+ /* vertical metrics from font units to 26.6 */
+ /* fractional pixels. Only relevant for scalable */
+ /* font formats. */
+ /* */
+ /* ascender :: The ascender in 26.6 fractional pixels. See */
+ /* @FT_FaceRec for the details. */
+ /* */
+ /* descender :: The descender in 26.6 fractional pixels. See */
+ /* @FT_FaceRec for the details. */
+ /* */
+ /* height :: The height in 26.6 fractional pixels. See */
+ /* @FT_FaceRec for the details. */
+ /* */
+ /* max_advance :: The maximal advance width in 26.6 fractional */
+ /* pixels. See @FT_FaceRec for the details. */
+ /* */
+ /* <Note> */
+ /* The scaling values, if relevant, are determined first during a */
+ /* size changing operation. The remaining fields are then set by the */
+ /* driver. For scalable formats, they are usually set to scaled */
+ /* values of the corresponding fields in @FT_FaceRec. */
+ /* */
+ /* Note that due to glyph hinting, these values might not be exact */
+ /* for certain fonts. Thus they must be treated as unreliable */
+ /* with an error margin of at least one pixel! */
+ /* */
+ /* Indeed, the only way to get the exact metrics is to render _all_ */
+ /* glyphs. As this would be a definite performance hit, it is up to */
+ /* client applications to perform such computations. */
+ /* */
+ /* The FT_Size_Metrics structure is valid for bitmap fonts also. */
+ /* */
+ typedef struct FT_Size_Metrics_
+ {
+ FT_UShort x_ppem; /* horizontal pixels per EM */
+ FT_UShort y_ppem; /* vertical pixels per EM */
+
+ FT_Fixed x_scale; /* scaling values used to convert font */
+ FT_Fixed y_scale; /* units to 26.6 fractional pixels */
+
+ FT_Pos ascender; /* ascender in 26.6 frac. pixels */
+ FT_Pos descender; /* descender in 26.6 frac. pixels */
+ FT_Pos height; /* text height in 26.6 frac. pixels */
+ FT_Pos max_advance; /* max horizontal advance, in 26.6 pixels */
+
+ } FT_Size_Metrics;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_SizeRec */
+ /* */
+ /* <Description> */
+ /* FreeType root size class structure. A size object models a face */
+ /* object at a given size. */
+ /* */
+ /* <Fields> */
+ /* face :: Handle to the parent face object. */
+ /* */
+ /* generic :: A typeless pointer, which is unused by the FreeType */
+ /* library or any of its drivers. It can be used by */
+ /* client applications to link their own data to each size */
+ /* object. */
+ /* */
+ /* metrics :: Metrics for this size object. This field is read-only. */
+ /* */
+ typedef struct FT_SizeRec_
+ {
+ FT_Face face; /* parent face object */
+ FT_Generic generic; /* generic pointer for client uses */
+ FT_Size_Metrics metrics; /* size metrics */
+ FT_Size_Internal internal;
+
+ } FT_SizeRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_SubGlyph */
+ /* */
+ /* <Description> */
+ /* The subglyph structure is an internal object used to describe */
+ /* subglyphs (for example, in the case of composites). */
+ /* */
+ /* <Note> */
+ /* The subglyph implementation is not part of the high-level API, */
+ /* hence the forward structure declaration. */
+ /* */
+ /* You can however retrieve subglyph information with */
+ /* @FT_Get_SubGlyph_Info. */
+ /* */
+ typedef struct FT_SubGlyphRec_* FT_SubGlyph;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Slot_Internal */
+ /* */
+ /* <Description> */
+ /* An opaque handle to an `FT_Slot_InternalRec' structure, used to */
+ /* model private data of a given @FT_GlyphSlot object. */
+ /* */
+ typedef struct FT_Slot_InternalRec_* FT_Slot_Internal;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_GlyphSlotRec */
+ /* */
+ /* <Description> */
+ /* FreeType root glyph slot class structure. A glyph slot is a */
+ /* container where individual glyphs can be loaded, be they in */
+ /* outline or bitmap format. */
+ /* */
+ /* <Fields> */
+ /* library :: A handle to the FreeType library instance */
+ /* this slot belongs to. */
+ /* */
+ /* face :: A handle to the parent face object. */
+ /* */
+ /* next :: In some cases (like some font tools), several */
+ /* glyph slots per face object can be a good */
+ /* thing. As this is rare, the glyph slots are */
+ /* listed through a direct, single-linked list */
+ /* using its `next' field. */
+ /* */
+ /* generic :: A typeless pointer which is unused by the */
+ /* FreeType library or any of its drivers. It */
+ /* can be used by client applications to link */
+ /* their own data to each glyph slot object. */
+ /* */
+ /* metrics :: The metrics of the last loaded glyph in the */
+ /* slot. The returned values depend on the last */
+ /* load flags (see the @FT_Load_Glyph API */
+ /* function) and can be expressed either in 26.6 */
+ /* fractional pixels or font units. */
+ /* */
+ /* Note that even when the glyph image is */
+ /* transformed, the metrics are not. */
+ /* */
+ /* linearHoriAdvance :: The advance width of the unhinted glyph. */
+ /* Its value is expressed in 16.16 fractional */
+ /* pixels, unless @FT_LOAD_LINEAR_DESIGN is set */
+ /* when loading the glyph. This field can be */
+ /* important to perform correct WYSIWYG layout. */
+ /* Only relevant for outline glyphs. */
+ /* */
+ /* linearVertAdvance :: The advance height of the unhinted glyph. */
+ /* Its value is expressed in 16.16 fractional */
+ /* pixels, unless @FT_LOAD_LINEAR_DESIGN is set */
+ /* when loading the glyph. This field can be */
+ /* important to perform correct WYSIWYG layout. */
+ /* Only relevant for outline glyphs. */
+ /* */
+ /* advance :: This is the transformed advance width for the */
+ /* glyph (in 26.6 fractional pixel format). */
+ /* */
+ /* format :: This field indicates the format of the image */
+ /* contained in the glyph slot. Typically */
+ /* @FT_GLYPH_FORMAT_BITMAP, */
+ /* @FT_GLYPH_FORMAT_OUTLINE, or */
+ /* @FT_GLYPH_FORMAT_COMPOSITE, but others are */
+ /* possible. */
+ /* */
+ /* bitmap :: This field is used as a bitmap descriptor */
+ /* when the slot format is */
+ /* @FT_GLYPH_FORMAT_BITMAP. Note that the */
+ /* address and content of the bitmap buffer can */
+ /* change between calls of @FT_Load_Glyph and a */
+ /* few other functions. */
+ /* */
+ /* bitmap_left :: This is the bitmap's left bearing expressed */
+ /* in integer pixels. Of course, this is only */
+ /* valid if the format is */
+ /* @FT_GLYPH_FORMAT_BITMAP. */
+ /* */
+ /* bitmap_top :: This is the bitmap's top bearing expressed in */
+ /* integer pixels. Remember that this is the */
+ /* distance from the baseline to the top-most */
+ /* glyph scanline, upwards y~coordinates being */
+ /* *positive*. */
+ /* */
+ /* outline :: The outline descriptor for the current glyph */
+ /* image if its format is */
+ /* @FT_GLYPH_FORMAT_OUTLINE. Once a glyph is */
+ /* loaded, `outline' can be transformed, */
+ /* distorted, embolded, etc. However, it must */
+ /* not be freed. */
+ /* */
+ /* num_subglyphs :: The number of subglyphs in a composite glyph. */
+ /* This field is only valid for the composite */
+ /* glyph format that should normally only be */
+ /* loaded with the @FT_LOAD_NO_RECURSE flag. */
+ /* For now this is internal to FreeType. */
+ /* */
+ /* subglyphs :: An array of subglyph descriptors for */
+ /* composite glyphs. There are `num_subglyphs' */
+ /* elements in there. Currently internal to */
+ /* FreeType. */
+ /* */
+ /* control_data :: Certain font drivers can also return the */
+ /* control data for a given glyph image (e.g. */
+ /* TrueType bytecode, Type~1 charstrings, etc.). */
+ /* This field is a pointer to such data. */
+ /* */
+ /* control_len :: This is the length in bytes of the control */
+ /* data. */
+ /* */
+ /* other :: Really wicked formats can use this pointer to */
+ /* present their own glyph image to client */
+ /* applications. Note that the application */
+ /* needs to know about the image format. */
+ /* */
+ /* lsb_delta :: The difference between hinted and unhinted */
+ /* left side bearing while autohinting is */
+ /* active. Zero otherwise. */
+ /* */
+ /* rsb_delta :: The difference between hinted and unhinted */
+ /* right side bearing while autohinting is */
+ /* active. Zero otherwise. */
+ /* */
+ /* <Note> */
+ /* If @FT_Load_Glyph is called with default flags (see */
+ /* @FT_LOAD_DEFAULT) the glyph image is loaded in the glyph slot in */
+ /* its native format (e.g., an outline glyph for TrueType and Type~1 */
+ /* formats). */
+ /* */
+ /* This image can later be converted into a bitmap by calling */
+ /* @FT_Render_Glyph. This function finds the current renderer for */
+ /* the native image's format, then invokes it. */
+ /* */
+ /* The renderer is in charge of transforming the native image through */
+ /* the slot's face transformation fields, then converting it into a */
+ /* bitmap that is returned in `slot->bitmap'. */
+ /* */
+ /* Note that `slot->bitmap_left' and `slot->bitmap_top' are also used */
+ /* to specify the position of the bitmap relative to the current pen */
+ /* position (e.g., coordinates (0,0) on the baseline). Of course, */
+ /* `slot->format' is also changed to @FT_GLYPH_FORMAT_BITMAP. */
+ /* */
+ /* <Note> */
+ /* Here a small pseudo code fragment which shows how to use */
+ /* `lsb_delta' and `rsb_delta': */
+ /* */
+ /* { */
+ /* FT_Pos origin_x = 0; */
+ /* FT_Pos prev_rsb_delta = 0; */
+ /* */
+ /* */
+ /* for all glyphs do */
+ /* <compute kern between current and previous glyph and add it to */
+ /* `origin_x'> */
+ /* */
+ /* <load glyph with `FT_Load_Glyph'> */
+ /* */
+ /* if ( prev_rsb_delta - face->glyph->lsb_delta >= 32 ) */
+ /* origin_x -= 64; */
+ /* else if ( prev_rsb_delta - face->glyph->lsb_delta < -32 ) */
+ /* origin_x += 64; */
+ /* */
+ /* prev_rsb_delta = face->glyph->rsb_delta; */
+ /* */
+ /* <save glyph image, or render glyph, or ...> */
+ /* */
+ /* origin_x += face->glyph->advance.x; */
+ /* endfor */
+ /* } */
+ /* */
+ typedef struct FT_GlyphSlotRec_
+ {
+ FT_Library library;
+ FT_Face face;
+ FT_GlyphSlot next;
+ FT_UInt reserved; /* retained for binary compatibility */
+ FT_Generic generic;
+
+ FT_Glyph_Metrics metrics;
+ FT_Fixed linearHoriAdvance;
+ FT_Fixed linearVertAdvance;
+ FT_Vector advance;
+
+ FT_Glyph_Format format;
+
+ FT_Bitmap bitmap;
+ FT_Int bitmap_left;
+ FT_Int bitmap_top;
+
+ FT_Outline outline;
+
+ FT_UInt num_subglyphs;
+ FT_SubGlyph subglyphs;
+
+ void* control_data;
+ long control_len;
+
+ FT_Pos lsb_delta;
+ FT_Pos rsb_delta;
+
+ void* other;
+
+ FT_Slot_Internal internal;
+
+ } FT_GlyphSlotRec;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /* */
+ /* F U N C T I O N S */
+ /* */
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Init_FreeType */
+ /* */
+ /* <Description> */
+ /* Initialize a new FreeType library object. The set of modules */
+ /* that are registered by this function is determined at build time. */
+ /* */
+ /* <Output> */
+ /* alibrary :: A handle to a new library object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Init_FreeType( FT_Library *alibrary );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Done_FreeType */
+ /* */
+ /* <Description> */
+ /* Destroy a given FreeType library object and all of its children, */
+ /* including resources, drivers, faces, sizes, etc. */
+ /* */
+ /* <Input> */
+ /* library :: A handle to the target library object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Done_FreeType( FT_Library library );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_OPEN_XXX */
+ /* */
+ /* <Description> */
+ /* A list of bit-field constants used within the `flags' field of the */
+ /* @FT_Open_Args structure. */
+ /* */
+ /* <Values> */
+ /* FT_OPEN_MEMORY :: This is a memory-based stream. */
+ /* */
+ /* FT_OPEN_STREAM :: Copy the stream from the `stream' field. */
+ /* */
+ /* FT_OPEN_PATHNAME :: Create a new input stream from a C~path */
+ /* name. */
+ /* */
+ /* FT_OPEN_DRIVER :: Use the `driver' field. */
+ /* */
+ /* FT_OPEN_PARAMS :: Use the `num_params' and `params' fields. */
+ /* */
+ /* ft_open_memory :: Deprecated; use @FT_OPEN_MEMORY instead. */
+ /* */
+ /* ft_open_stream :: Deprecated; use @FT_OPEN_STREAM instead. */
+ /* */
+ /* ft_open_pathname :: Deprecated; use @FT_OPEN_PATHNAME instead. */
+ /* */
+ /* ft_open_driver :: Deprecated; use @FT_OPEN_DRIVER instead. */
+ /* */
+ /* ft_open_params :: Deprecated; use @FT_OPEN_PARAMS instead. */
+ /* */
+ /* <Note> */
+ /* The `FT_OPEN_MEMORY', `FT_OPEN_STREAM', and `FT_OPEN_PATHNAME' */
+ /* flags are mutually exclusive. */
+ /* */
+#define FT_OPEN_MEMORY 0x1
+#define FT_OPEN_STREAM 0x2
+#define FT_OPEN_PATHNAME 0x4
+#define FT_OPEN_DRIVER 0x8
+#define FT_OPEN_PARAMS 0x10
+
+#define ft_open_memory FT_OPEN_MEMORY /* deprecated */
+#define ft_open_stream FT_OPEN_STREAM /* deprecated */
+#define ft_open_pathname FT_OPEN_PATHNAME /* deprecated */
+#define ft_open_driver FT_OPEN_DRIVER /* deprecated */
+#define ft_open_params FT_OPEN_PARAMS /* deprecated */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Parameter */
+ /* */
+ /* <Description> */
+ /* A simple structure used to pass more or less generic parameters to */
+ /* @FT_Open_Face. */
+ /* */
+ /* <Fields> */
+ /* tag :: A four-byte identification tag. */
+ /* */
+ /* data :: A pointer to the parameter data. */
+ /* */
+ /* <Note> */
+ /* The ID and function of parameters are driver-specific. */
+ /* */
+ typedef struct FT_Parameter_
+ {
+ FT_ULong tag;
+ FT_Pointer data;
+
+ } FT_Parameter;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Open_Args */
+ /* */
+ /* <Description> */
+ /* A structure used to indicate how to open a new font file or */
+ /* stream. A pointer to such a structure can be used as a parameter */
+ /* for the functions @FT_Open_Face and @FT_Attach_Stream. */
+ /* */
+ /* <Fields> */
+ /* flags :: A set of bit flags indicating how to use the */
+ /* structure. */
+ /* */
+ /* memory_base :: The first byte of the file in memory. */
+ /* */
+ /* memory_size :: The size in bytes of the file in memory. */
+ /* */
+ /* pathname :: A pointer to an 8-bit file pathname. */
+ /* */
+ /* stream :: A handle to a source stream object. */
+ /* */
+ /* driver :: This field is exclusively used by @FT_Open_Face; */
+ /* it simply specifies the font driver to use to open */
+ /* the face. If set to~0, FreeType tries to load the */
+ /* face with each one of the drivers in its list. */
+ /* */
+ /* num_params :: The number of extra parameters. */
+ /* */
+ /* params :: Extra parameters passed to the font driver when */
+ /* opening a new face. */
+ /* */
+ /* <Note> */
+ /* The stream type is determined by the contents of `flags' which */
+ /* are tested in the following order by @FT_Open_Face: */
+ /* */
+ /* If the `FT_OPEN_MEMORY' bit is set, assume that this is a */
+ /* memory file of `memory_size' bytes, located at `memory_address'. */
+ /* The data are are not copied, and the client is responsible for */
+ /* releasing and destroying them _after_ the corresponding call to */
+ /* @FT_Done_Face. */
+ /* */
+ /* Otherwise, if the `FT_OPEN_STREAM' bit is set, assume that a */
+ /* custom input stream `stream' is used. */
+ /* */
+ /* Otherwise, if the `FT_OPEN_PATHNAME' bit is set, assume that this */
+ /* is a normal file and use `pathname' to open it. */
+ /* */
+ /* If the `FT_OPEN_DRIVER' bit is set, @FT_Open_Face only tries to */
+ /* open the file with the driver whose handler is in `driver'. */
+ /* */
+ /* If the `FT_OPEN_PARAMS' bit is set, the parameters given by */
+ /* `num_params' and `params' is used. They are ignored otherwise. */
+ /* */
+ /* Ideally, both the `pathname' and `params' fields should be tagged */
+ /* as `const'; this is missing for API backwards compatibility. In */
+ /* other words, applications should treat them as read-only. */
+ /* */
+ typedef struct FT_Open_Args_
+ {
+ FT_UInt flags;
+ const FT_Byte* memory_base;
+ FT_Long memory_size;
+ FT_String* pathname;
+ FT_Stream stream;
+ FT_Module driver;
+ FT_Int num_params;
+ FT_Parameter* params;
+
+ } FT_Open_Args;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_New_Face */
+ /* */
+ /* <Description> */
+ /* This function calls @FT_Open_Face to open a font by its pathname. */
+ /* */
+ /* <InOut> */
+ /* library :: A handle to the library resource. */
+ /* */
+ /* <Input> */
+ /* pathname :: A path to the font file. */
+ /* */
+ /* face_index :: The index of the face within the font. The first */
+ /* face has index~0. */
+ /* */
+ /* <Output> */
+ /* aface :: A handle to a new face object. If `face_index' is */
+ /* greater than or equal to zero, it must be non-NULL. */
+ /* See @FT_Open_Face for more details. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_New_Face( FT_Library library,
+ const char* filepathname,
+ FT_Long face_index,
+ FT_Face *aface );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_New_Memory_Face */
+ /* */
+ /* <Description> */
+ /* This function calls @FT_Open_Face to open a font which has been */
+ /* loaded into memory. */
+ /* */
+ /* <InOut> */
+ /* library :: A handle to the library resource. */
+ /* */
+ /* <Input> */
+ /* file_base :: A pointer to the beginning of the font data. */
+ /* */
+ /* file_size :: The size of the memory chunk used by the font data. */
+ /* */
+ /* face_index :: The index of the face within the font. The first */
+ /* face has index~0. */
+ /* */
+ /* <Output> */
+ /* aface :: A handle to a new face object. If `face_index' is */
+ /* greater than or equal to zero, it must be non-NULL. */
+ /* See @FT_Open_Face for more details. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* You must not deallocate the memory before calling @FT_Done_Face. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_New_Memory_Face( FT_Library library,
+ const FT_Byte* file_base,
+ FT_Long file_size,
+ FT_Long face_index,
+ FT_Face *aface );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Open_Face */
+ /* */
+ /* <Description> */
+ /* Create a face object from a given resource described by */
+ /* @FT_Open_Args. */
+ /* */
+ /* <InOut> */
+ /* library :: A handle to the library resource. */
+ /* */
+ /* <Input> */
+ /* args :: A pointer to an `FT_Open_Args' structure which must */
+ /* be filled by the caller. */
+ /* */
+ /* face_index :: The index of the face within the font. The first */
+ /* face has index~0. */
+ /* */
+ /* <Output> */
+ /* aface :: A handle to a new face object. If `face_index' is */
+ /* greater than or equal to zero, it must be non-NULL. */
+ /* See note below. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* Unlike FreeType 1.x, this function automatically creates a glyph */
+ /* slot for the face object which can be accessed directly through */
+ /* `face->glyph'. */
+ /* */
+ /* FT_Open_Face can be used to quickly check whether the font */
+ /* format of a given font resource is supported by FreeType. If the */
+ /* `face_index' field is negative, the function's return value is~0 */
+ /* if the font format is recognized, or non-zero otherwise; */
+ /* the function returns a more or less empty face handle in `*aface' */
+ /* (if `aface' isn't NULL). The only useful field in this special */
+ /* case is `face->num_faces' which gives the number of faces within */
+ /* the font file. After examination, the returned @FT_Face structure */
+ /* should be deallocated with a call to @FT_Done_Face. */
+ /* */
+ /* Each new face object created with this function also owns a */
+ /* default @FT_Size object, accessible as `face->size'. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Open_Face( FT_Library library,
+ const FT_Open_Args* args,
+ FT_Long face_index,
+ FT_Face *aface );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Attach_File */
+ /* */
+ /* <Description> */
+ /* This function calls @FT_Attach_Stream to attach a file. */
+ /* */
+ /* <InOut> */
+ /* face :: The target face object. */
+ /* */
+ /* <Input> */
+ /* filepathname :: The pathname. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Attach_File( FT_Face face,
+ const char* filepathname );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Attach_Stream */
+ /* */
+ /* <Description> */
+ /* `Attach' data to a face object. Normally, this is used to read */
+ /* additional information for the face object. For example, you can */
+ /* attach an AFM file that comes with a Type~1 font to get the */
+ /* kerning values and other metrics. */
+ /* */
+ /* <InOut> */
+ /* face :: The target face object. */
+ /* */
+ /* <Input> */
+ /* parameters :: A pointer to @FT_Open_Args which must be filled by */
+ /* the caller. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* The meaning of the `attach' (i.e., what really happens when the */
+ /* new file is read) is not fixed by FreeType itself. It really */
+ /* depends on the font format (and thus the font driver). */
+ /* */
+ /* Client applications are expected to know what they are doing */
+ /* when invoking this function. Most drivers simply do not implement */
+ /* file attachments. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Attach_Stream( FT_Face face,
+ FT_Open_Args* parameters );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Done_Face */
+ /* */
+ /* <Description> */
+ /* Discard a given face object, as well as all of its child slots and */
+ /* sizes. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to a target face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Done_Face( FT_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Select_Size */
+ /* */
+ /* <Description> */
+ /* Select a bitmap strike. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to a target face object. */
+ /* */
+ /* <Input> */
+ /* strike_index :: The index of the bitmap strike in the */
+ /* `available_sizes' field of @FT_FaceRec structure. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Select_Size( FT_Face face,
+ FT_Int strike_index );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Size_Request_Type */
+ /* */
+ /* <Description> */
+ /* An enumeration type that lists the supported size request types. */
+ /* */
+ /* <Values> */
+ /* FT_SIZE_REQUEST_TYPE_NOMINAL :: */
+ /* The nominal size. The `units_per_EM' field of @FT_FaceRec is */
+ /* used to determine both scaling values. */
+ /* */
+ /* FT_SIZE_REQUEST_TYPE_REAL_DIM :: */
+ /* The real dimension. The sum of the the `Ascender' and (minus */
+ /* of) the `Descender' fields of @FT_FaceRec are used to determine */
+ /* both scaling values. */
+ /* */
+ /* FT_SIZE_REQUEST_TYPE_BBOX :: */
+ /* The font bounding box. The width and height of the `bbox' field */
+ /* of @FT_FaceRec are used to determine the horizontal and vertical */
+ /* scaling value, respectively. */
+ /* */
+ /* FT_SIZE_REQUEST_TYPE_CELL :: */
+ /* The `max_advance_width' field of @FT_FaceRec is used to */
+ /* determine the horizontal scaling value; the vertical scaling */
+ /* value is determined the same way as */
+ /* @FT_SIZE_REQUEST_TYPE_REAL_DIM does. Finally, both scaling */
+ /* values are set to the smaller one. This type is useful if you */
+ /* want to specify the font size for, say, a window of a given */
+ /* dimension and 80x24 cells. */
+ /* */
+ /* FT_SIZE_REQUEST_TYPE_SCALES :: */
+ /* Specify the scaling values directly. */
+ /* */
+ /* <Note> */
+ /* The above descriptions only apply to scalable formats. For bitmap */
+ /* formats, the behaviour is up to the driver. */
+ /* */
+ /* See the note section of @FT_Size_Metrics if you wonder how size */
+ /* requesting relates to scaling values. */
+ /* */
+ typedef enum FT_Size_Request_Type_
+ {
+ FT_SIZE_REQUEST_TYPE_NOMINAL,
+ FT_SIZE_REQUEST_TYPE_REAL_DIM,
+ FT_SIZE_REQUEST_TYPE_BBOX,
+ FT_SIZE_REQUEST_TYPE_CELL,
+ FT_SIZE_REQUEST_TYPE_SCALES,
+
+ FT_SIZE_REQUEST_TYPE_MAX
+
+ } FT_Size_Request_Type;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Size_RequestRec */
+ /* */
+ /* <Description> */
+ /* A structure used to model a size request. */
+ /* */
+ /* <Fields> */
+ /* type :: See @FT_Size_Request_Type. */
+ /* */
+ /* width :: The desired width. */
+ /* */
+ /* height :: The desired height. */
+ /* */
+ /* horiResolution :: The horizontal resolution. If set to zero, */
+ /* `width' is treated as a 26.6 fractional pixel */
+ /* value. */
+ /* */
+ /* vertResolution :: The vertical resolution. If set to zero, */
+ /* `height' is treated as a 26.6 fractional pixel */
+ /* value. */
+ /* */
+ /* <Note> */
+ /* If `width' is zero, then the horizontal scaling value is set equal */
+ /* to the vertical scaling value, and vice versa. */
+ /* */
+ typedef struct FT_Size_RequestRec_
+ {
+ FT_Size_Request_Type type;
+ FT_Long width;
+ FT_Long height;
+ FT_UInt horiResolution;
+ FT_UInt vertResolution;
+
+ } FT_Size_RequestRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Size_Request */
+ /* */
+ /* <Description> */
+ /* A handle to a size request structure. */
+ /* */
+ typedef struct FT_Size_RequestRec_ *FT_Size_Request;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Request_Size */
+ /* */
+ /* <Description> */
+ /* Resize the scale of the active @FT_Size object in a face. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to a target face object. */
+ /* */
+ /* <Input> */
+ /* req :: A pointer to a @FT_Size_RequestRec. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* Although drivers may select the bitmap strike matching the */
+ /* request, you should not rely on this if you intend to select a */
+ /* particular bitmap strike. Use @FT_Select_Size instead in that */
+ /* case. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Request_Size( FT_Face face,
+ FT_Size_Request req );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Set_Char_Size */
+ /* */
+ /* <Description> */
+ /* This function calls @FT_Request_Size to request the nominal size */
+ /* (in points). */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to a target face object. */
+ /* */
+ /* <Input> */
+ /* char_width :: The nominal width, in 26.6 fractional points. */
+ /* */
+ /* char_height :: The nominal height, in 26.6 fractional points. */
+ /* */
+ /* horz_resolution :: The horizontal resolution in dpi. */
+ /* */
+ /* vert_resolution :: The vertical resolution in dpi. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* If either the character width or height is zero, it is set equal */
+ /* to the other value. */
+ /* */
+ /* If either the horizontal or vertical resolution is zero, it is set */
+ /* equal to the other value. */
+ /* */
+ /* A character width or height smaller than 1pt is set to 1pt; if */
+ /* both resolution values are zero, they are set to 72dpi. */
+ /* */
+ /* Don't use this function if you are using the FreeType cache API. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Set_Char_Size( FT_Face face,
+ FT_F26Dot6 char_width,
+ FT_F26Dot6 char_height,
+ FT_UInt horz_resolution,
+ FT_UInt vert_resolution );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Set_Pixel_Sizes */
+ /* */
+ /* <Description> */
+ /* This function calls @FT_Request_Size to request the nominal size */
+ /* (in pixels). */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* <Input> */
+ /* pixel_width :: The nominal width, in pixels. */
+ /* */
+ /* pixel_height :: The nominal height, in pixels. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Set_Pixel_Sizes( FT_Face face,
+ FT_UInt pixel_width,
+ FT_UInt pixel_height );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Load_Glyph */
+ /* */
+ /* <Description> */
+ /* A function used to load a single glyph into the glyph slot of a */
+ /* face object. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the target face object where the glyph */
+ /* is loaded. */
+ /* */
+ /* <Input> */
+ /* glyph_index :: The index of the glyph in the font file. For */
+ /* CID-keyed fonts (either in PS or in CFF format) */
+ /* this argument specifies the CID value. */
+ /* */
+ /* load_flags :: A flag indicating what to load for this glyph. The */
+ /* @FT_LOAD_XXX constants can be used to control the */
+ /* glyph loading process (e.g., whether the outline */
+ /* should be scaled, whether to load bitmaps or not, */
+ /* whether to hint the outline, etc). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* The loaded glyph may be transformed. See @FT_Set_Transform for */
+ /* the details. */
+ /* */
+ /* For subsetted CID-keyed fonts, `FT_Err_Invalid_Argument' is */
+ /* returned for invalid CID values (this is, for CID values which */
+ /* don't have a corresponding glyph in the font). See the discussion */
+ /* of the @FT_FACE_FLAG_CID_KEYED flag for more details. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Load_Glyph( FT_Face face,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Load_Char */
+ /* */
+ /* <Description> */
+ /* A function used to load a single glyph into the glyph slot of a */
+ /* face object, according to its character code. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to a target face object where the glyph */
+ /* is loaded. */
+ /* */
+ /* <Input> */
+ /* char_code :: The glyph's character code, according to the */
+ /* current charmap used in the face. */
+ /* */
+ /* load_flags :: A flag indicating what to load for this glyph. The */
+ /* @FT_LOAD_XXX constants can be used to control the */
+ /* glyph loading process (e.g., whether the outline */
+ /* should be scaled, whether to load bitmaps or not, */
+ /* whether to hint the outline, etc). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* This function simply calls @FT_Get_Char_Index and @FT_Load_Glyph. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Load_Char( FT_Face face,
+ FT_ULong char_code,
+ FT_Int32 load_flags );
+
+
+ /*************************************************************************
+ *
+ * @enum:
+ * FT_LOAD_XXX
+ *
+ * @description:
+ * A list of bit-field constants used with @FT_Load_Glyph to indicate
+ * what kind of operations to perform during glyph loading.
+ *
+ * @values:
+ * FT_LOAD_DEFAULT ::
+ * Corresponding to~0, this value is used as the default glyph load
+ * operation. In this case, the following happens:
+ *
+ * 1. FreeType looks for a bitmap for the glyph corresponding to the
+ * face's current size. If one is found, the function returns.
+ * The bitmap data can be accessed from the glyph slot (see note
+ * below).
+ *
+ * 2. If no embedded bitmap is searched or found, FreeType looks for a
+ * scalable outline. If one is found, it is loaded from the font
+ * file, scaled to device pixels, then `hinted' to the pixel grid
+ * in order to optimize it. The outline data can be accessed from
+ * the glyph slot (see note below).
+ *
+ * Note that by default, the glyph loader doesn't render outlines into
+ * bitmaps. The following flags are used to modify this default
+ * behaviour to more specific and useful cases.
+ *
+ * FT_LOAD_NO_SCALE ::
+ * Don't scale the outline glyph loaded, but keep it in font units.
+ *
+ * This flag implies @FT_LOAD_NO_HINTING and @FT_LOAD_NO_BITMAP, and
+ * unsets @FT_LOAD_RENDER.
+ *
+ * FT_LOAD_NO_HINTING ::
+ * Disable hinting. This generally generates `blurrier' bitmap glyph
+ * when the glyph is rendered in any of the anti-aliased modes. See
+ * also the note below.
+ *
+ * This flag is implied by @FT_LOAD_NO_SCALE.
+ *
+ * FT_LOAD_RENDER ::
+ * Call @FT_Render_Glyph after the glyph is loaded. By default, the
+ * glyph is rendered in @FT_RENDER_MODE_NORMAL mode. This can be
+ * overridden by @FT_LOAD_TARGET_XXX or @FT_LOAD_MONOCHROME.
+ *
+ * This flag is unset by @FT_LOAD_NO_SCALE.
+ *
+ * FT_LOAD_NO_BITMAP ::
+ * Ignore bitmap strikes when loading. Bitmap-only fonts ignore this
+ * flag.
+ *
+ * @FT_LOAD_NO_SCALE always sets this flag.
+ *
+ * FT_LOAD_VERTICAL_LAYOUT ::
+ * Load the glyph for vertical text layout. _Don't_ use it as it is
+ * problematic currently.
+ *
+ * FT_LOAD_FORCE_AUTOHINT ::
+ * Indicates that the auto-hinter is preferred over the font's native
+ * hinter. See also the note below.
+ *
+ * FT_LOAD_CROP_BITMAP ::
+ * Indicates that the font driver should crop the loaded bitmap glyph
+ * (i.e., remove all space around its black bits). Not all drivers
+ * implement this.
+ *
+ * FT_LOAD_PEDANTIC ::
+ * Indicates that the font driver should perform pedantic verifications
+ * during glyph loading. This is mostly used to detect broken glyphs
+ * in fonts. By default, FreeType tries to handle broken fonts also.
+ *
+ * FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ::
+ * Indicates that the font driver should ignore the global advance
+ * width defined in the font. By default, that value is used as the
+ * advance width for all glyphs when the face has
+ * @FT_FACE_FLAG_FIXED_WIDTH set.
+ *
+ * This flag exists for historical reasons (to support buggy CJK
+ * fonts).
+ *
+ * FT_LOAD_NO_RECURSE ::
+ * This flag is only used internally. It merely indicates that the
+ * font driver should not load composite glyphs recursively. Instead,
+ * it should set the `num_subglyph' and `subglyphs' values of the
+ * glyph slot accordingly, and set `glyph->format' to
+ * @FT_GLYPH_FORMAT_COMPOSITE.
+ *
+ * The description of sub-glyphs is not available to client
+ * applications for now.
+ *
+ * This flag implies @FT_LOAD_NO_SCALE and @FT_LOAD_IGNORE_TRANSFORM.
+ *
+ * FT_LOAD_IGNORE_TRANSFORM ::
+ * Indicates that the transform matrix set by @FT_Set_Transform should
+ * be ignored.
+ *
+ * FT_LOAD_MONOCHROME ::
+ * This flag is used with @FT_LOAD_RENDER to indicate that you want to
+ * render an outline glyph to a 1-bit monochrome bitmap glyph, with
+ * 8~pixels packed into each byte of the bitmap data.
+ *
+ * Note that this has no effect on the hinting algorithm used. You
+ * should rather use @FT_LOAD_TARGET_MONO so that the
+ * monochrome-optimized hinting algorithm is used.
+ *
+ * FT_LOAD_LINEAR_DESIGN ::
+ * Indicates that the `linearHoriAdvance' and `linearVertAdvance'
+ * fields of @FT_GlyphSlotRec should be kept in font units. See
+ * @FT_GlyphSlotRec for details.
+ *
+ * FT_LOAD_NO_AUTOHINT ::
+ * Disable auto-hinter. See also the note below.
+ *
+ * @note:
+ * By default, hinting is enabled and the font's native hinter (see
+ * @FT_FACE_FLAG_HINTER) is preferred over the auto-hinter. You can
+ * disable hinting by setting @FT_LOAD_NO_HINTING or change the
+ * precedence by setting @FT_LOAD_FORCE_AUTOHINT. You can also set
+ * @FT_LOAD_NO_AUTOHINT in case you don't want the auto-hinter to be
+ * used at all.
+ *
+ * See the description of @FT_FACE_FLAG_TRICKY for a special exception
+ * (affecting only a handful of Asian fonts).
+ *
+ * Besides deciding which hinter to use, you can also decide which
+ * hinting algorithm to use. See @FT_LOAD_TARGET_XXX for details.
+ *
+ */
+#define FT_LOAD_DEFAULT 0x0
+#define FT_LOAD_NO_SCALE 0x1
+#define FT_LOAD_NO_HINTING 0x2
+#define FT_LOAD_RENDER 0x4
+#define FT_LOAD_NO_BITMAP 0x8
+#define FT_LOAD_VERTICAL_LAYOUT 0x10
+#define FT_LOAD_FORCE_AUTOHINT 0x20
+#define FT_LOAD_CROP_BITMAP 0x40
+#define FT_LOAD_PEDANTIC 0x80
+#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH 0x200
+#define FT_LOAD_NO_RECURSE 0x400
+#define FT_LOAD_IGNORE_TRANSFORM 0x800
+#define FT_LOAD_MONOCHROME 0x1000
+#define FT_LOAD_LINEAR_DESIGN 0x2000
+#define FT_LOAD_NO_AUTOHINT 0x8000U
+
+ /* */
+
+ /* used internally only by certain font drivers! */
+#define FT_LOAD_ADVANCE_ONLY 0x100
+#define FT_LOAD_SBITS_ONLY 0x4000
+
+
+ /**************************************************************************
+ *
+ * @enum:
+ * FT_LOAD_TARGET_XXX
+ *
+ * @description:
+ * A list of values that are used to select a specific hinting algorithm
+ * to use by the hinter. You should OR one of these values to your
+ * `load_flags' when calling @FT_Load_Glyph.
+ *
+ * Note that font's native hinters may ignore the hinting algorithm you
+ * have specified (e.g., the TrueType bytecode interpreter). You can set
+ * @FT_LOAD_FORCE_AUTOHINT to ensure that the auto-hinter is used.
+ *
+ * Also note that @FT_LOAD_TARGET_LIGHT is an exception, in that it
+ * always implies @FT_LOAD_FORCE_AUTOHINT.
+ *
+ * @values:
+ * FT_LOAD_TARGET_NORMAL ::
+ * This corresponds to the default hinting algorithm, optimized for
+ * standard gray-level rendering. For monochrome output, use
+ * @FT_LOAD_TARGET_MONO instead.
+ *
+ * FT_LOAD_TARGET_LIGHT ::
+ * A lighter hinting algorithm for non-monochrome modes. Many
+ * generated glyphs are more fuzzy but better resemble its original
+ * shape. A bit like rendering on Mac OS~X.
+ *
+ * As a special exception, this target implies @FT_LOAD_FORCE_AUTOHINT.
+ *
+ * FT_LOAD_TARGET_MONO ::
+ * Strong hinting algorithm that should only be used for monochrome
+ * output. The result is probably unpleasant if the glyph is rendered
+ * in non-monochrome modes.
+ *
+ * FT_LOAD_TARGET_LCD ::
+ * A variant of @FT_LOAD_TARGET_NORMAL optimized for horizontally
+ * decimated LCD displays.
+ *
+ * FT_LOAD_TARGET_LCD_V ::
+ * A variant of @FT_LOAD_TARGET_NORMAL optimized for vertically
+ * decimated LCD displays.
+ *
+ * @note:
+ * You should use only _one_ of the FT_LOAD_TARGET_XXX values in your
+ * `load_flags'. They can't be ORed.
+ *
+ * If @FT_LOAD_RENDER is also set, the glyph is rendered in the
+ * corresponding mode (i.e., the mode which matches the used algorithm
+ * best) unless @FT_LOAD_MONOCHROME is set.
+ *
+ * You can use a hinting algorithm that doesn't correspond to the same
+ * rendering mode. As an example, it is possible to use the `light'
+ * hinting algorithm and have the results rendered in horizontal LCD
+ * pixel mode, with code like
+ *
+ * {
+ * FT_Load_Glyph( face, glyph_index,
+ * load_flags | FT_LOAD_TARGET_LIGHT );
+ *
+ * FT_Render_Glyph( face->glyph, FT_RENDER_MODE_LCD );
+ * }
+ *
+ */
+#define FT_LOAD_TARGET_( x ) ( (FT_Int32)( (x) & 15 ) << 16 )
+
+#define FT_LOAD_TARGET_NORMAL FT_LOAD_TARGET_( FT_RENDER_MODE_NORMAL )
+#define FT_LOAD_TARGET_LIGHT FT_LOAD_TARGET_( FT_RENDER_MODE_LIGHT )
+#define FT_LOAD_TARGET_MONO FT_LOAD_TARGET_( FT_RENDER_MODE_MONO )
+#define FT_LOAD_TARGET_LCD FT_LOAD_TARGET_( FT_RENDER_MODE_LCD )
+#define FT_LOAD_TARGET_LCD_V FT_LOAD_TARGET_( FT_RENDER_MODE_LCD_V )
+
+
+ /**************************************************************************
+ *
+ * @macro:
+ * FT_LOAD_TARGET_MODE
+ *
+ * @description:
+ * Return the @FT_Render_Mode corresponding to a given
+ * @FT_LOAD_TARGET_XXX value.
+ *
+ */
+#define FT_LOAD_TARGET_MODE( x ) ( (FT_Render_Mode)( ( (x) >> 16 ) & 15 ) )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Set_Transform */
+ /* */
+ /* <Description> */
+ /* A function used to set the transformation that is applied to glyph */
+ /* images when they are loaded into a glyph slot through */
+ /* @FT_Load_Glyph. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* <Input> */
+ /* matrix :: A pointer to the transformation's 2x2 matrix. Use~0 for */
+ /* the identity matrix. */
+ /* delta :: A pointer to the translation vector. Use~0 for the null */
+ /* vector. */
+ /* */
+ /* <Note> */
+ /* The transformation is only applied to scalable image formats after */
+ /* the glyph has been loaded. It means that hinting is unaltered by */
+ /* the transformation and is performed on the character size given in */
+ /* the last call to @FT_Set_Char_Size or @FT_Set_Pixel_Sizes. */
+ /* */
+ /* Note that this also transforms the `face.glyph.advance' field, but */
+ /* *not* the values in `face.glyph.metrics'. */
+ /* */
+ FT_EXPORT( void )
+ FT_Set_Transform( FT_Face face,
+ FT_Matrix* matrix,
+ FT_Vector* delta );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Render_Mode */
+ /* */
+ /* <Description> */
+ /* An enumeration type that lists the render modes supported by */
+ /* FreeType~2. Each mode corresponds to a specific type of scanline */
+ /* conversion performed on the outline. */
+ /* */
+ /* For bitmap fonts and embedded bitmaps the `bitmap->pixel_mode' */
+ /* field in the @FT_GlyphSlotRec structure gives the format of the */
+ /* returned bitmap. */
+ /* */
+ /* All modes except @FT_RENDER_MODE_MONO use 256 levels of opacity. */
+ /* */
+ /* <Values> */
+ /* FT_RENDER_MODE_NORMAL :: */
+ /* This is the default render mode; it corresponds to 8-bit */
+ /* anti-aliased bitmaps. */
+ /* */
+ /* FT_RENDER_MODE_LIGHT :: */
+ /* This is equivalent to @FT_RENDER_MODE_NORMAL. It is only */
+ /* defined as a separate value because render modes are also used */
+ /* indirectly to define hinting algorithm selectors. See */
+ /* @FT_LOAD_TARGET_XXX for details. */
+ /* */
+ /* FT_RENDER_MODE_MONO :: */
+ /* This mode corresponds to 1-bit bitmaps (with 2~levels of */
+ /* opacity). */
+ /* */
+ /* FT_RENDER_MODE_LCD :: */
+ /* This mode corresponds to horizontal RGB and BGR sub-pixel */
+ /* displays like LCD screens. It produces 8-bit bitmaps that are */
+ /* 3~times the width of the original glyph outline in pixels, and */
+ /* which use the @FT_PIXEL_MODE_LCD mode. */
+ /* */
+ /* FT_RENDER_MODE_LCD_V :: */
+ /* This mode corresponds to vertical RGB and BGR sub-pixel displays */
+ /* (like PDA screens, rotated LCD displays, etc.). It produces */
+ /* 8-bit bitmaps that are 3~times the height of the original */
+ /* glyph outline in pixels and use the @FT_PIXEL_MODE_LCD_V mode. */
+ /* */
+ /* <Note> */
+ /* The LCD-optimized glyph bitmaps produced by FT_Render_Glyph can be */
+ /* filtered to reduce color-fringes by using @FT_Library_SetLcdFilter */
+ /* (not active in the default builds). It is up to the caller to */
+ /* either call @FT_Library_SetLcdFilter (if available) or do the */
+ /* filtering itself. */
+ /* */
+ /* The selected render mode only affects vector glyphs of a font. */
+ /* Embedded bitmaps often have a different pixel mode like */
+ /* @FT_PIXEL_MODE_MONO. You can use @FT_Bitmap_Convert to transform */
+ /* them into 8-bit pixmaps. */
+ /* */
+ typedef enum FT_Render_Mode_
+ {
+ FT_RENDER_MODE_NORMAL = 0,
+ FT_RENDER_MODE_LIGHT,
+ FT_RENDER_MODE_MONO,
+ FT_RENDER_MODE_LCD,
+ FT_RENDER_MODE_LCD_V,
+
+ FT_RENDER_MODE_MAX
+
+ } FT_Render_Mode;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* ft_render_mode_xxx */
+ /* */
+ /* <Description> */
+ /* These constants are deprecated. Use the corresponding */
+ /* @FT_Render_Mode values instead. */
+ /* */
+ /* <Values> */
+ /* ft_render_mode_normal :: see @FT_RENDER_MODE_NORMAL */
+ /* ft_render_mode_mono :: see @FT_RENDER_MODE_MONO */
+ /* */
+#define ft_render_mode_normal FT_RENDER_MODE_NORMAL
+#define ft_render_mode_mono FT_RENDER_MODE_MONO
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Render_Glyph */
+ /* */
+ /* <Description> */
+ /* Convert a given glyph image to a bitmap. It does so by inspecting */
+ /* the glyph image format, finding the relevant renderer, and */
+ /* invoking it. */
+ /* */
+ /* <InOut> */
+ /* slot :: A handle to the glyph slot containing the image to */
+ /* convert. */
+ /* */
+ /* <Input> */
+ /* render_mode :: This is the render mode used to render the glyph */
+ /* image into a bitmap. See @FT_Render_Mode for a */
+ /* list of possible values. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Render_Glyph( FT_GlyphSlot slot,
+ FT_Render_Mode render_mode );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Kerning_Mode */
+ /* */
+ /* <Description> */
+ /* An enumeration used to specify which kerning values to return in */
+ /* @FT_Get_Kerning. */
+ /* */
+ /* <Values> */
+ /* FT_KERNING_DEFAULT :: Return scaled and grid-fitted kerning */
+ /* distances (value is~0). */
+ /* */
+ /* FT_KERNING_UNFITTED :: Return scaled but un-grid-fitted kerning */
+ /* distances. */
+ /* */
+ /* FT_KERNING_UNSCALED :: Return the kerning vector in original font */
+ /* units. */
+ /* */
+ typedef enum FT_Kerning_Mode_
+ {
+ FT_KERNING_DEFAULT = 0,
+ FT_KERNING_UNFITTED,
+ FT_KERNING_UNSCALED
+
+ } FT_Kerning_Mode;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Const> */
+ /* ft_kerning_default */
+ /* */
+ /* <Description> */
+ /* This constant is deprecated. Please use @FT_KERNING_DEFAULT */
+ /* instead. */
+ /* */
+#define ft_kerning_default FT_KERNING_DEFAULT
+
+
+ /*************************************************************************/
+ /* */
+ /* <Const> */
+ /* ft_kerning_unfitted */
+ /* */
+ /* <Description> */
+ /* This constant is deprecated. Please use @FT_KERNING_UNFITTED */
+ /* instead. */
+ /* */
+#define ft_kerning_unfitted FT_KERNING_UNFITTED
+
+
+ /*************************************************************************/
+ /* */
+ /* <Const> */
+ /* ft_kerning_unscaled */
+ /* */
+ /* <Description> */
+ /* This constant is deprecated. Please use @FT_KERNING_UNSCALED */
+ /* instead. */
+ /* */
+#define ft_kerning_unscaled FT_KERNING_UNSCALED
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Kerning */
+ /* */
+ /* <Description> */
+ /* Return the kerning vector between two glyphs of a same face. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to a source face object. */
+ /* */
+ /* left_glyph :: The index of the left glyph in the kern pair. */
+ /* */
+ /* right_glyph :: The index of the right glyph in the kern pair. */
+ /* */
+ /* kern_mode :: See @FT_Kerning_Mode for more information. */
+ /* Determines the scale and dimension of the returned */
+ /* kerning vector. */
+ /* */
+ /* <Output> */
+ /* akerning :: The kerning vector. This is either in font units */
+ /* or in pixels (26.6 format) for scalable formats, */
+ /* and in pixels for fixed-sizes formats. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* Only horizontal layouts (left-to-right & right-to-left) are */
+ /* supported by this method. Other layouts, or more sophisticated */
+ /* kernings, are out of the scope of this API function -- they can be */
+ /* implemented through format-specific interfaces. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Get_Kerning( FT_Face face,
+ FT_UInt left_glyph,
+ FT_UInt right_glyph,
+ FT_UInt kern_mode,
+ FT_Vector *akerning );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Track_Kerning */
+ /* */
+ /* <Description> */
+ /* Return the track kerning for a given face object at a given size. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to a source face object. */
+ /* */
+ /* point_size :: The point size in 16.16 fractional points. */
+ /* */
+ /* degree :: The degree of tightness. */
+ /* */
+ /* <Output> */
+ /* akerning :: The kerning in 16.16 fractional points. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Get_Track_Kerning( FT_Face face,
+ FT_Fixed point_size,
+ FT_Int degree,
+ FT_Fixed* akerning );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Glyph_Name */
+ /* */
+ /* <Description> */
+ /* Retrieve the ASCII name of a given glyph in a face. This only */
+ /* works for those faces where @FT_HAS_GLYPH_NAMES(face) returns~1. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to a source face object. */
+ /* */
+ /* glyph_index :: The glyph index. */
+ /* */
+ /* buffer_max :: The maximal number of bytes available in the */
+ /* buffer. */
+ /* */
+ /* <Output> */
+ /* buffer :: A pointer to a target buffer where the name is */
+ /* copied to. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* An error is returned if the face doesn't provide glyph names or if */
+ /* the glyph index is invalid. In all cases of failure, the first */
+ /* byte of `buffer' is set to~0 to indicate an empty name. */
+ /* */
+ /* The glyph name is truncated to fit within the buffer if it is too */
+ /* long. The returned string is always zero-terminated. */
+ /* */
+ /* This function is not compiled within the library if the config */
+ /* macro `FT_CONFIG_OPTION_NO_GLYPH_NAMES' is defined in */
+ /* `include/freetype/config/ftoptions.h'. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Get_Glyph_Name( FT_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Postscript_Name */
+ /* */
+ /* <Description> */
+ /* Retrieve the ASCII PostScript name of a given face, if available. */
+ /* This only works with PostScript and TrueType fonts. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* <Return> */
+ /* A pointer to the face's PostScript name. NULL if unavailable. */
+ /* */
+ /* <Note> */
+ /* The returned pointer is owned by the face and is destroyed with */
+ /* it. */
+ /* */
+ FT_EXPORT( const char* )
+ FT_Get_Postscript_Name( FT_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Select_Charmap */
+ /* */
+ /* <Description> */
+ /* Select a given charmap by its encoding tag (as listed in */
+ /* `freetype.h'). */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* <Input> */
+ /* encoding :: A handle to the selected encoding. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* This function returns an error if no charmap in the face */
+ /* corresponds to the encoding queried here. */
+ /* */
+ /* Because many fonts contain more than a single cmap for Unicode */
+ /* encoding, this function has some special code to select the one */
+ /* which covers Unicode best (`best' in the sense that a UCS-4 cmap */
+ /* is preferred to a UCS-2 cmap). It is thus preferable to */
+ /* @FT_Set_Charmap in this case. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Select_Charmap( FT_Face face,
+ FT_Encoding encoding );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Set_Charmap */
+ /* */
+ /* <Description> */
+ /* Select a given charmap for character code to glyph index mapping. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* <Input> */
+ /* charmap :: A handle to the selected charmap. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* This function returns an error if the charmap is not part of */
+ /* the face (i.e., if it is not listed in the `face->charmaps' */
+ /* table). */
+ /* */
+ /* It also fails if a type~14 charmap is selected. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Set_Charmap( FT_Face face,
+ FT_CharMap charmap );
+
+
+ /*************************************************************************
+ *
+ * @function:
+ * FT_Get_Charmap_Index
+ *
+ * @description:
+ * Retrieve index of a given charmap.
+ *
+ * @input:
+ * charmap ::
+ * A handle to a charmap.
+ *
+ * @return:
+ * The index into the array of character maps within the face to which
+ * `charmap' belongs.
+ *
+ */
+ FT_EXPORT( FT_Int )
+ FT_Get_Charmap_Index( FT_CharMap charmap );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Char_Index */
+ /* */
+ /* <Description> */
+ /* Return the glyph index of a given character code. This function */
+ /* uses a charmap object to do the mapping. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* charcode :: The character code. */
+ /* */
+ /* <Return> */
+ /* The glyph index. 0~means `undefined character code'. */
+ /* */
+ /* <Note> */
+ /* If you use FreeType to manipulate the contents of font files */
+ /* directly, be aware that the glyph index returned by this function */
+ /* doesn't always correspond to the internal indices used within */
+ /* the file. This is done to ensure that value~0 always corresponds */
+ /* to the `missing glyph'. */
+ /* */
+ FT_EXPORT( FT_UInt )
+ FT_Get_Char_Index( FT_Face face,
+ FT_ULong charcode );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_First_Char */
+ /* */
+ /* <Description> */
+ /* This function is used to return the first character code in the */
+ /* current charmap of a given face. It also returns the */
+ /* corresponding glyph index. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* <Output> */
+ /* agindex :: Glyph index of first character code. 0~if charmap is */
+ /* empty. */
+ /* */
+ /* <Return> */
+ /* The charmap's first character code. */
+ /* */
+ /* <Note> */
+ /* You should use this function with @FT_Get_Next_Char to be able to */
+ /* parse all character codes available in a given charmap. The code */
+ /* should look like this: */
+ /* */
+ /* { */
+ /* FT_ULong charcode; */
+ /* FT_UInt gindex; */
+ /* */
+ /* */
+ /* charcode = FT_Get_First_Char( face, &gindex ); */
+ /* while ( gindex != 0 ) */
+ /* { */
+ /* ... do something with (charcode,gindex) pair ... */
+ /* */
+ /* charcode = FT_Get_Next_Char( face, charcode, &gindex ); */
+ /* } */
+ /* } */
+ /* */
+ /* Note that `*agindex' is set to~0 if the charmap is empty. The */
+ /* result itself can be~0 in two cases: if the charmap is empty or */
+ /* if the value~0 is the first valid character code. */
+ /* */
+ FT_EXPORT( FT_ULong )
+ FT_Get_First_Char( FT_Face face,
+ FT_UInt *agindex );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Next_Char */
+ /* */
+ /* <Description> */
+ /* This function is used to return the next character code in the */
+ /* current charmap of a given face following the value `char_code', */
+ /* as well as the corresponding glyph index. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* char_code :: The starting character code. */
+ /* */
+ /* <Output> */
+ /* agindex :: Glyph index of next character code. 0~if charmap */
+ /* is empty. */
+ /* */
+ /* <Return> */
+ /* The charmap's next character code. */
+ /* */
+ /* <Note> */
+ /* You should use this function with @FT_Get_First_Char to walk */
+ /* over all character codes available in a given charmap. See the */
+ /* note for this function for a simple code example. */
+ /* */
+ /* Note that `*agindex' is set to~0 when there are no more codes in */
+ /* the charmap. */
+ /* */
+ FT_EXPORT( FT_ULong )
+ FT_Get_Next_Char( FT_Face face,
+ FT_ULong char_code,
+ FT_UInt *agindex );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Name_Index */
+ /* */
+ /* <Description> */
+ /* Return the glyph index of a given glyph name. This function uses */
+ /* driver specific objects to do the translation. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* glyph_name :: The glyph name. */
+ /* */
+ /* <Return> */
+ /* The glyph index. 0~means `undefined character code'. */
+ /* */
+ FT_EXPORT( FT_UInt )
+ FT_Get_Name_Index( FT_Face face,
+ FT_String* glyph_name );
+
+
+ /*************************************************************************
+ *
+ * @macro:
+ * FT_SUBGLYPH_FLAG_XXX
+ *
+ * @description:
+ * A list of constants used to describe subglyphs. Please refer to the
+ * TrueType specification for the meaning of the various flags.
+ *
+ * @values:
+ * FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS ::
+ * FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ::
+ * FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID ::
+ * FT_SUBGLYPH_FLAG_SCALE ::
+ * FT_SUBGLYPH_FLAG_XY_SCALE ::
+ * FT_SUBGLYPH_FLAG_2X2 ::
+ * FT_SUBGLYPH_FLAG_USE_MY_METRICS ::
+ *
+ */
+#define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS 1
+#define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES 2
+#define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID 4
+#define FT_SUBGLYPH_FLAG_SCALE 8
+#define FT_SUBGLYPH_FLAG_XY_SCALE 0x40
+#define FT_SUBGLYPH_FLAG_2X2 0x80
+#define FT_SUBGLYPH_FLAG_USE_MY_METRICS 0x200
+
+
+ /*************************************************************************
+ *
+ * @func:
+ * FT_Get_SubGlyph_Info
+ *
+ * @description:
+ * Retrieve a description of a given subglyph. Only use it if
+ * `glyph->format' is @FT_GLYPH_FORMAT_COMPOSITE; an error is
+ * returned otherwise.
+ *
+ * @input:
+ * glyph ::
+ * The source glyph slot.
+ *
+ * sub_index ::
+ * The index of the subglyph. Must be less than
+ * `glyph->num_subglyphs'.
+ *
+ * @output:
+ * p_index ::
+ * The glyph index of the subglyph.
+ *
+ * p_flags ::
+ * The subglyph flags, see @FT_SUBGLYPH_FLAG_XXX.
+ *
+ * p_arg1 ::
+ * The subglyph's first argument (if any).
+ *
+ * p_arg2 ::
+ * The subglyph's second argument (if any).
+ *
+ * p_transform ::
+ * The subglyph transformation (if any).
+ *
+ * @return:
+ * FreeType error code. 0~means success.
+ *
+ * @note:
+ * The values of `*p_arg1', `*p_arg2', and `*p_transform' must be
+ * interpreted depending on the flags returned in `*p_flags'. See the
+ * TrueType specification for details.
+ *
+ */
+ FT_EXPORT( FT_Error )
+ FT_Get_SubGlyph_Info( FT_GlyphSlot glyph,
+ FT_UInt sub_index,
+ FT_Int *p_index,
+ FT_UInt *p_flags,
+ FT_Int *p_arg1,
+ FT_Int *p_arg2,
+ FT_Matrix *p_transform );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_FSTYPE_XXX */
+ /* */
+ /* <Description> */
+ /* A list of bit flags used in the `fsType' field of the OS/2 table */
+ /* in a TrueType or OpenType font and the `FSType' entry in a */
+ /* PostScript font. These bit flags are returned by */
+ /* @FT_Get_FSType_Flags; they inform client applications of embedding */
+ /* and subsetting restrictions associated with a font. */
+ /* */
+ /* See http://www.adobe.com/devnet/acrobat/pdfs/FontPolicies.pdf for */
+ /* more details. */
+ /* */
+ /* <Values> */
+ /* FT_FSTYPE_INSTALLABLE_EMBEDDING :: */
+ /* Fonts with no fsType bit set may be embedded and permanently */
+ /* installed on the remote system by an application. */
+ /* */
+ /* FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING :: */
+ /* Fonts that have only this bit set must not be modified, embedded */
+ /* or exchanged in any manner without first obtaining permission of */
+ /* the font software copyright owner. */
+ /* */
+ /* FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING :: */
+ /* If this bit is set, the font may be embedded and temporarily */
+ /* loaded on the remote system. Documents containing Preview & */
+ /* Print fonts must be opened `read-only'; no edits can be applied */
+ /* to the document. */
+ /* */
+ /* FT_FSTYPE_EDITABLE_EMBEDDING :: */
+ /* If this bit is set, the font may be embedded but must only be */
+ /* installed temporarily on other systems. In contrast to Preview */
+ /* & Print fonts, documents containing editable fonts may be opened */
+ /* for reading, editing is permitted, and changes may be saved. */
+ /* */
+ /* FT_FSTYPE_NO_SUBSETTING :: */
+ /* If this bit is set, the font may not be subsetted prior to */
+ /* embedding. */
+ /* */
+ /* FT_FSTYPE_BITMAP_EMBEDDING_ONLY :: */
+ /* If this bit is set, only bitmaps contained in the font may be */
+ /* embedded; no outline data may be embedded. If there are no */
+ /* bitmaps available in the font, then the font is unembeddable. */
+ /* */
+ /* <Note> */
+ /* While the fsType flags can indicate that a font may be embedded, a */
+ /* license with the font vendor may be separately required to use the */
+ /* font in this way. */
+ /* */
+#define FT_FSTYPE_INSTALLABLE_EMBEDDING 0x0000
+#define FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING 0x0002
+#define FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING 0x0004
+#define FT_FSTYPE_EDITABLE_EMBEDDING 0x0008
+#define FT_FSTYPE_NO_SUBSETTING 0x0100
+#define FT_FSTYPE_BITMAP_EMBEDDING_ONLY 0x0200
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_FSType_Flags */
+ /* */
+ /* <Description> */
+ /* Return the fsType flags for a font. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* <Return> */
+ /* The fsType flags, @FT_FSTYPE_XXX. */
+ /* */
+ /* <Note> */
+ /* Use this function rather than directly reading the `fs_type' field */
+ /* in the @PS_FontInfoRec structure which is only guaranteed to */
+ /* return the correct results for Type~1 fonts. */
+ /* */
+ FT_EXPORT( FT_UShort )
+ FT_Get_FSType_Flags( FT_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* glyph_variants */
+ /* */
+ /* <Title> */
+ /* Glyph Variants */
+ /* */
+ /* <Abstract> */
+ /* The FreeType~2 interface to Unicode Ideographic Variation */
+ /* Sequences (IVS), using the SFNT cmap format~14. */
+ /* */
+ /* <Description> */
+ /* Many CJK characters have variant forms. They are a sort of grey */
+ /* area somewhere between being totally irrelevant and semantically */
+ /* distinct; for this reason, the Unicode consortium decided to */
+ /* introduce Ideographic Variation Sequences (IVS), consisting of a */
+ /* Unicode base character and one of 240 variant selectors */
+ /* (U+E0100-U+E01EF), instead of further extending the already huge */
+ /* code range for CJK characters. */
+ /* */
+ /* An IVS is registered and unique; for further details please refer */
+ /* to Unicode Technical Report #37, the Ideographic Variation */
+ /* Database. To date (October 2007), the character with the most */
+ /* variants is U+908A, having 8~such IVS. */
+ /* */
+ /* Adobe and MS decided to support IVS with a new cmap subtable */
+ /* (format~14). It is an odd subtable because it is not a mapping of */
+ /* input code points to glyphs, but contains lists of all variants */
+ /* supported by the font. */
+ /* */
+ /* A variant may be either `default' or `non-default'. A default */
+ /* variant is the one you will get for that code point if you look it */
+ /* up in the standard Unicode cmap. A non-default variant is a */
+ /* different glyph. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Face_GetCharVariantIndex */
+ /* */
+ /* <Description> */
+ /* Return the glyph index of a given character code as modified by */
+ /* the variation selector. */
+ /* */
+ /* <Input> */
+ /* face :: */
+ /* A handle to the source face object. */
+ /* */
+ /* charcode :: */
+ /* The character code point in Unicode. */
+ /* */
+ /* variantSelector :: */
+ /* The Unicode code point of the variation selector. */
+ /* */
+ /* <Return> */
+ /* The glyph index. 0~means either `undefined character code', or */
+ /* `undefined selector code', or `no variation selector cmap */
+ /* subtable', or `current CharMap is not Unicode'. */
+ /* */
+ /* <Note> */
+ /* If you use FreeType to manipulate the contents of font files */
+ /* directly, be aware that the glyph index returned by this function */
+ /* doesn't always correspond to the internal indices used within */
+ /* the file. This is done to ensure that value~0 always corresponds */
+ /* to the `missing glyph'. */
+ /* */
+ /* This function is only meaningful if */
+ /* a) the font has a variation selector cmap sub table, */
+ /* and */
+ /* b) the current charmap has a Unicode encoding. */
+ /* */
+ /* <Since> */
+ /* 2.3.6 */
+ /* */
+ FT_EXPORT( FT_UInt )
+ FT_Face_GetCharVariantIndex( FT_Face face,
+ FT_ULong charcode,
+ FT_ULong variantSelector );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Face_GetCharVariantIsDefault */
+ /* */
+ /* <Description> */
+ /* Check whether this variant of this Unicode character is the one to */
+ /* be found in the `cmap'. */
+ /* */
+ /* <Input> */
+ /* face :: */
+ /* A handle to the source face object. */
+ /* */
+ /* charcode :: */
+ /* The character codepoint in Unicode. */
+ /* */
+ /* variantSelector :: */
+ /* The Unicode codepoint of the variation selector. */
+ /* */
+ /* <Return> */
+ /* 1~if found in the standard (Unicode) cmap, 0~if found in the */
+ /* variation selector cmap, or -1 if it is not a variant. */
+ /* */
+ /* <Note> */
+ /* This function is only meaningful if the font has a variation */
+ /* selector cmap subtable. */
+ /* */
+ /* <Since> */
+ /* 2.3.6 */
+ /* */
+ FT_EXPORT( FT_Int )
+ FT_Face_GetCharVariantIsDefault( FT_Face face,
+ FT_ULong charcode,
+ FT_ULong variantSelector );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Face_GetVariantSelectors */
+ /* */
+ /* <Description> */
+ /* Return a zero-terminated list of Unicode variant selectors found */
+ /* in the font. */
+ /* */
+ /* <Input> */
+ /* face :: */
+ /* A handle to the source face object. */
+ /* */
+ /* <Return> */
+ /* A pointer to an array of selector code points, or NULL if there is */
+ /* no valid variant selector cmap subtable. */
+ /* */
+ /* <Note> */
+ /* The last item in the array is~0; the array is owned by the */
+ /* @FT_Face object but can be overwritten or released on the next */
+ /* call to a FreeType function. */
+ /* */
+ /* <Since> */
+ /* 2.3.6 */
+ /* */
+ FT_EXPORT( FT_UInt32* )
+ FT_Face_GetVariantSelectors( FT_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Face_GetVariantsOfChar */
+ /* */
+ /* <Description> */
+ /* Return a zero-terminated list of Unicode variant selectors found */
+ /* for the specified character code. */
+ /* */
+ /* <Input> */
+ /* face :: */
+ /* A handle to the source face object. */
+ /* */
+ /* charcode :: */
+ /* The character codepoint in Unicode. */
+ /* */
+ /* <Return> */
+ /* A pointer to an array of variant selector code points which are */
+ /* active for the given character, or NULL if the corresponding list */
+ /* is empty. */
+ /* */
+ /* <Note> */
+ /* The last item in the array is~0; the array is owned by the */
+ /* @FT_Face object but can be overwritten or released on the next */
+ /* call to a FreeType function. */
+ /* */
+ /* <Since> */
+ /* 2.3.6 */
+ /* */
+ FT_EXPORT( FT_UInt32* )
+ FT_Face_GetVariantsOfChar( FT_Face face,
+ FT_ULong charcode );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Face_GetCharsOfVariant */
+ /* */
+ /* <Description> */
+ /* Return a zero-terminated list of Unicode character codes found for */
+ /* the specified variant selector. */
+ /* */
+ /* <Input> */
+ /* face :: */
+ /* A handle to the source face object. */
+ /* */
+ /* variantSelector :: */
+ /* The variant selector code point in Unicode. */
+ /* */
+ /* <Return> */
+ /* A list of all the code points which are specified by this selector */
+ /* (both default and non-default codes are returned) or NULL if there */
+ /* is no valid cmap or the variant selector is invalid. */
+ /* */
+ /* <Note> */
+ /* The last item in the array is~0; the array is owned by the */
+ /* @FT_Face object but can be overwritten or released on the next */
+ /* call to a FreeType function. */
+ /* */
+ /* <Since> */
+ /* 2.3.6 */
+ /* */
+ FT_EXPORT( FT_UInt32* )
+ FT_Face_GetCharsOfVariant( FT_Face face,
+ FT_ULong variantSelector );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* computations */
+ /* */
+ /* <Title> */
+ /* Computations */
+ /* */
+ /* <Abstract> */
+ /* Crunching fixed numbers and vectors. */
+ /* */
+ /* <Description> */
+ /* This section contains various functions used to perform */
+ /* computations on 16.16 fixed-float numbers or 2d vectors. */
+ /* */
+ /* <Order> */
+ /* FT_MulDiv */
+ /* FT_MulFix */
+ /* FT_DivFix */
+ /* FT_RoundFix */
+ /* FT_CeilFix */
+ /* FT_FloorFix */
+ /* FT_Vector_Transform */
+ /* FT_Matrix_Multiply */
+ /* FT_Matrix_Invert */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_MulDiv */
+ /* */
+ /* <Description> */
+ /* A very simple function used to perform the computation `(a*b)/c' */
+ /* with maximal accuracy (it uses a 64-bit intermediate integer */
+ /* whenever necessary). */
+ /* */
+ /* This function isn't necessarily as fast as some processor specific */
+ /* operations, but is at least completely portable. */
+ /* */
+ /* <Input> */
+ /* a :: The first multiplier. */
+ /* b :: The second multiplier. */
+ /* c :: The divisor. */
+ /* */
+ /* <Return> */
+ /* The result of `(a*b)/c'. This function never traps when trying to */
+ /* divide by zero; it simply returns `MaxInt' or `MinInt' depending */
+ /* on the signs of `a' and `b'. */
+ /* */
+ FT_EXPORT( FT_Long )
+ FT_MulDiv( FT_Long a,
+ FT_Long b,
+ FT_Long c );
+
+
+ /* */
+
+ /* The following #if 0 ... #endif is for the documentation formatter, */
+ /* hiding the internal `FT_MULFIX_INLINED' macro. */
+
+#if 0
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_MulFix */
+ /* */
+ /* <Description> */
+ /* A very simple function used to perform the computation */
+ /* `(a*b)/0x10000' with maximal accuracy. Most of the time this is */
+ /* used to multiply a given value by a 16.16 fixed float factor. */
+ /* */
+ /* <Input> */
+ /* a :: The first multiplier. */
+ /* b :: The second multiplier. Use a 16.16 factor here whenever */
+ /* possible (see note below). */
+ /* */
+ /* <Return> */
+ /* The result of `(a*b)/0x10000'. */
+ /* */
+ /* <Note> */
+ /* This function has been optimized for the case where the absolute */
+ /* value of `a' is less than 2048, and `b' is a 16.16 scaling factor. */
+ /* As this happens mainly when scaling from notional units to */
+ /* fractional pixels in FreeType, it resulted in noticeable speed */
+ /* improvements between versions 2.x and 1.x. */
+ /* */
+ /* As a conclusion, always try to place a 16.16 factor as the */
+ /* _second_ argument of this function; this can make a great */
+ /* difference. */
+ /* */
+ FT_EXPORT( FT_Long )
+ FT_MulFix( FT_Long a,
+ FT_Long b );
+
+ /* */
+#endif
+
+#ifdef FT_MULFIX_INLINED
+#define FT_MulFix( a, b ) FT_MULFIX_INLINED( a, b )
+#else
+ FT_EXPORT( FT_Long )
+ FT_MulFix( FT_Long a,
+ FT_Long b );
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_DivFix */
+ /* */
+ /* <Description> */
+ /* A very simple function used to perform the computation */
+ /* `(a*0x10000)/b' with maximal accuracy. Most of the time, this is */
+ /* used to divide a given value by a 16.16 fixed float factor. */
+ /* */
+ /* <Input> */
+ /* a :: The first multiplier. */
+ /* b :: The second multiplier. Use a 16.16 factor here whenever */
+ /* possible (see note below). */
+ /* */
+ /* <Return> */
+ /* The result of `(a*0x10000)/b'. */
+ /* */
+ /* <Note> */
+ /* The optimization for FT_DivFix() is simple: If (a~<<~16) fits in */
+ /* 32~bits, then the division is computed directly. Otherwise, we */
+ /* use a specialized version of @FT_MulDiv. */
+ /* */
+ FT_EXPORT( FT_Long )
+ FT_DivFix( FT_Long a,
+ FT_Long b );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_RoundFix */
+ /* */
+ /* <Description> */
+ /* A very simple function used to round a 16.16 fixed number. */
+ /* */
+ /* <Input> */
+ /* a :: The number to be rounded. */
+ /* */
+ /* <Return> */
+ /* The result of `(a + 0x8000) & -0x10000'. */
+ /* */
+ FT_EXPORT( FT_Fixed )
+ FT_RoundFix( FT_Fixed a );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_CeilFix */
+ /* */
+ /* <Description> */
+ /* A very simple function used to compute the ceiling function of a */
+ /* 16.16 fixed number. */
+ /* */
+ /* <Input> */
+ /* a :: The number for which the ceiling function is to be computed. */
+ /* */
+ /* <Return> */
+ /* The result of `(a + 0x10000 - 1) & -0x10000'. */
+ /* */
+ FT_EXPORT( FT_Fixed )
+ FT_CeilFix( FT_Fixed a );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_FloorFix */
+ /* */
+ /* <Description> */
+ /* A very simple function used to compute the floor function of a */
+ /* 16.16 fixed number. */
+ /* */
+ /* <Input> */
+ /* a :: The number for which the floor function is to be computed. */
+ /* */
+ /* <Return> */
+ /* The result of `a & -0x10000'. */
+ /* */
+ FT_EXPORT( FT_Fixed )
+ FT_FloorFix( FT_Fixed a );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Vector_Transform */
+ /* */
+ /* <Description> */
+ /* Transform a single vector through a 2x2 matrix. */
+ /* */
+ /* <InOut> */
+ /* vector :: The target vector to transform. */
+ /* */
+ /* <Input> */
+ /* matrix :: A pointer to the source 2x2 matrix. */
+ /* */
+ /* <Note> */
+ /* The result is undefined if either `vector' or `matrix' is invalid. */
+ /* */
+ FT_EXPORT( void )
+ FT_Vector_Transform( FT_Vector* vec,
+ const FT_Matrix* matrix );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* version */
+ /* */
+ /* <Title> */
+ /* FreeType Version */
+ /* */
+ /* <Abstract> */
+ /* Functions and macros related to FreeType versions. */
+ /* */
+ /* <Description> */
+ /* Note that those functions and macros are of limited use because */
+ /* even a new release of FreeType with only documentation changes */
+ /* increases the version number. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************
+ *
+ * @enum:
+ * FREETYPE_XXX
+ *
+ * @description:
+ * These three macros identify the FreeType source code version.
+ * Use @FT_Library_Version to access them at runtime.
+ *
+ * @values:
+ * FREETYPE_MAJOR :: The major version number.
+ * FREETYPE_MINOR :: The minor version number.
+ * FREETYPE_PATCH :: The patch level.
+ *
+ * @note:
+ * The version number of FreeType if built as a dynamic link library
+ * with the `libtool' package is _not_ controlled by these three
+ * macros.
+ *
+ */
+#define FREETYPE_MAJOR 2
+#define FREETYPE_MINOR 3
+#define FREETYPE_PATCH 9
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Library_Version */
+ /* */
+ /* <Description> */
+ /* Return the version of the FreeType library being used. This is */
+ /* useful when dynamically linking to the library, since one cannot */
+ /* use the macros @FREETYPE_MAJOR, @FREETYPE_MINOR, and */
+ /* @FREETYPE_PATCH. */
+ /* */
+ /* <Input> */
+ /* library :: A source library handle. */
+ /* */
+ /* <Output> */
+ /* amajor :: The major version number. */
+ /* */
+ /* aminor :: The minor version number. */
+ /* */
+ /* apatch :: The patch version number. */
+ /* */
+ /* <Note> */
+ /* The reason why this function takes a `library' argument is because */
+ /* certain programs implement library initialization in a custom way */
+ /* that doesn't use @FT_Init_FreeType. */
+ /* */
+ /* In such cases, the library version might not be available before */
+ /* the library object has been created. */
+ /* */
+ FT_EXPORT( void )
+ FT_Library_Version( FT_Library library,
+ FT_Int *amajor,
+ FT_Int *aminor,
+ FT_Int *apatch );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Face_CheckTrueTypePatents */
+ /* */
+ /* <Description> */
+ /* Parse all bytecode instructions of a TrueType font file to check */
+ /* whether any of the patented opcodes are used. This is only useful */
+ /* if you want to be able to use the unpatented hinter with */
+ /* fonts that do *not* use these opcodes. */
+ /* */
+ /* Note that this function parses *all* glyph instructions in the */
+ /* font file, which may be slow. */
+ /* */
+ /* <Input> */
+ /* face :: A face handle. */
+ /* */
+ /* <Return> */
+ /* 1~if this is a TrueType font that uses one of the patented */
+ /* opcodes, 0~otherwise. */
+ /* */
+ /* <Since> */
+ /* 2.3.5 */
+ /* */
+ FT_EXPORT( FT_Bool )
+ FT_Face_CheckTrueTypePatents( FT_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Face_SetUnpatentedHinting */
+ /* */
+ /* <Description> */
+ /* Enable or disable the unpatented hinter for a given face. */
+ /* Only enable it if you have determined that the face doesn't */
+ /* use any patented opcodes (see @FT_Face_CheckTrueTypePatents). */
+ /* */
+ /* <Input> */
+ /* face :: A face handle. */
+ /* */
+ /* value :: New boolean setting. */
+ /* */
+ /* <Return> */
+ /* The old setting value. This will always be false if this is not */
+ /* an SFNT font, or if the unpatented hinter is not compiled in this */
+ /* instance of the library. */
+ /* */
+ /* <Since> */
+ /* 2.3.5 */
+ /* */
+ FT_EXPORT( FT_Bool )
+ FT_Face_SetUnpatentedHinting( FT_Face face,
+ FT_Bool value );
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FREETYPE_H__ */
+
+
+/* END */
diff --git a/guilib/freetype2/include/freetype/ftcache.h b/guilib/freetype2/include/freetype/ftcache.h
new file mode 100644
index 0000000000..230d6f2a8c
--- /dev/null
+++ b/guilib/freetype2/include/freetype/ftcache.h
@@ -0,0 +1,1125 @@
+/***************************************************************************/
+/* */
+/* ftcache.h */
+/* */
+/* FreeType Cache subsystem (specification). */
+/* */
+/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTCACHE_H__
+#define __FTCACHE_H__
+
+
+#include <ft2build.h>
+#include FT_GLYPH_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************
+ *
+ * <Section>
+ * cache_subsystem
+ *
+ * <Title>
+ * Cache Sub-System
+ *
+ * <Abstract>
+ * How to cache face, size, and glyph data with FreeType~2.
+ *
+ * <Description>
+ * This section describes the FreeType~2 cache sub-system, which is used
+ * to limit the number of concurrently opened @FT_Face and @FT_Size
+ * objects, as well as caching information like character maps and glyph
+ * images while limiting their maximum memory usage.
+ *
+ * Note that all types and functions begin with the `FTC_' prefix.
+ *
+ * The cache is highly portable and thus doesn't know anything about the
+ * fonts installed on your system, or how to access them. This implies
+ * the following scheme:
+ *
+ * First, available or installed font faces are uniquely identified by
+ * @FTC_FaceID values, provided to the cache by the client. Note that
+ * the cache only stores and compares these values, and doesn't try to
+ * interpret them in any way.
+ *
+ * Second, the cache calls, only when needed, a client-provided function
+ * to convert a @FTC_FaceID into a new @FT_Face object. The latter is
+ * then completely managed by the cache, including its termination
+ * through @FT_Done_Face.
+ *
+ * Clients are free to map face IDs to anything else. The most simple
+ * usage is to associate them to a (pathname,face_index) pair that is
+ * used to call @FT_New_Face. However, more complex schemes are also
+ * possible.
+ *
+ * Note that for the cache to work correctly, the face ID values must be
+ * *persistent*, which means that the contents they point to should not
+ * change at runtime, or that their value should not become invalid.
+ *
+ * If this is unavoidable (e.g., when a font is uninstalled at runtime),
+ * you should call @FTC_Manager_RemoveFaceID as soon as possible, to let
+ * the cache get rid of any references to the old @FTC_FaceID it may
+ * keep internally. Failure to do so will lead to incorrect behaviour
+ * or even crashes.
+ *
+ * To use the cache, start with calling @FTC_Manager_New to create a new
+ * @FTC_Manager object, which models a single cache instance. You can
+ * then look up @FT_Face and @FT_Size objects with
+ * @FTC_Manager_LookupFace and @FTC_Manager_LookupSize, respectively.
+ *
+ * If you want to use the charmap caching, call @FTC_CMapCache_New, then
+ * later use @FTC_CMapCache_Lookup to perform the equivalent of
+ * @FT_Get_Char_Index, only much faster.
+ *
+ * If you want to use the @FT_Glyph caching, call @FTC_ImageCache, then
+ * later use @FTC_ImageCache_Lookup to retrieve the corresponding
+ * @FT_Glyph objects from the cache.
+ *
+ * If you need lots of small bitmaps, it is much more memory efficient
+ * to call @FTC_SBitCache_New followed by @FTC_SBitCache_Lookup. This
+ * returns @FTC_SBitRec structures, which are used to store small
+ * bitmaps directly. (A small bitmap is one whose metrics and
+ * dimensions all fit into 8-bit integers).
+ *
+ * We hope to also provide a kerning cache in the near future.
+ *
+ *
+ * <Order>
+ * FTC_Manager
+ * FTC_FaceID
+ * FTC_Face_Requester
+ *
+ * FTC_Manager_New
+ * FTC_Manager_Reset
+ * FTC_Manager_Done
+ * FTC_Manager_LookupFace
+ * FTC_Manager_LookupSize
+ * FTC_Manager_RemoveFaceID
+ *
+ * FTC_Node
+ * FTC_Node_Unref
+ *
+ * FTC_ImageCache
+ * FTC_ImageCache_New
+ * FTC_ImageCache_Lookup
+ *
+ * FTC_SBit
+ * FTC_SBitCache
+ * FTC_SBitCache_New
+ * FTC_SBitCache_Lookup
+ *
+ * FTC_CMapCache
+ * FTC_CMapCache_New
+ * FTC_CMapCache_Lookup
+ *
+ *************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** BASIC TYPE DEFINITIONS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************
+ *
+ * @type: FTC_FaceID
+ *
+ * @description:
+ * An opaque pointer type that is used to identity face objects. The
+ * contents of such objects is application-dependent.
+ *
+ * These pointers are typically used to point to a user-defined
+ * structure containing a font file path, and face index.
+ *
+ * @note:
+ * Never use NULL as a valid @FTC_FaceID.
+ *
+ * Face IDs are passed by the client to the cache manager, which calls,
+ * when needed, the @FTC_Face_Requester to translate them into new
+ * @FT_Face objects.
+ *
+ * If the content of a given face ID changes at runtime, or if the value
+ * becomes invalid (e.g., when uninstalling a font), you should
+ * immediately call @FTC_Manager_RemoveFaceID before any other cache
+ * function.
+ *
+ * Failure to do so will result in incorrect behaviour or even
+ * memory leaks and crashes.
+ */
+ typedef FT_Pointer FTC_FaceID;
+
+
+ /************************************************************************
+ *
+ * @functype:
+ * FTC_Face_Requester
+ *
+ * @description:
+ * A callback function provided by client applications. It is used by
+ * the cache manager to translate a given @FTC_FaceID into a new valid
+ * @FT_Face object, on demand.
+ *
+ * <Input>
+ * face_id ::
+ * The face ID to resolve.
+ *
+ * library ::
+ * A handle to a FreeType library object.
+ *
+ * req_data ::
+ * Application-provided request data (see note below).
+ *
+ * <Output>
+ * aface ::
+ * A new @FT_Face handle.
+ *
+ * <Return>
+ * FreeType error code. 0~means success.
+ *
+ * <Note>
+ * The third parameter `req_data' is the same as the one passed by the
+ * client when @FTC_Manager_New is called.
+ *
+ * The face requester should not perform funny things on the returned
+ * face object, like creating a new @FT_Size for it, or setting a
+ * transformation through @FT_Set_Transform!
+ */
+ typedef FT_Error
+ (*FTC_Face_Requester)( FTC_FaceID face_id,
+ FT_Library library,
+ FT_Pointer request_data,
+ FT_Face* aface );
+
+ /* */
+
+#define FT_POINTER_TO_ULONG( p ) ( (FT_ULong)(FT_Pointer)(p) )
+
+#define FTC_FACE_ID_HASH( i ) \
+ ((FT_UInt32)(( FT_POINTER_TO_ULONG( i ) >> 3 ) ^ \
+ ( FT_POINTER_TO_ULONG( i ) << 7 ) ) )
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CACHE MANAGER OBJECT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FTC_Manager */
+ /* */
+ /* <Description> */
+ /* This object corresponds to one instance of the cache-subsystem. */
+ /* It is used to cache one or more @FT_Face objects, along with */
+ /* corresponding @FT_Size objects. */
+ /* */
+ /* The manager intentionally limits the total number of opened */
+ /* @FT_Face and @FT_Size objects to control memory usage. See the */
+ /* `max_faces' and `max_sizes' parameters of @FTC_Manager_New. */
+ /* */
+ /* The manager is also used to cache `nodes' of various types while */
+ /* limiting their total memory usage. */
+ /* */
+ /* All limitations are enforced by keeping lists of managed objects */
+ /* in most-recently-used order, and flushing old nodes to make room */
+ /* for new ones. */
+ /* */
+ typedef struct FTC_ManagerRec_* FTC_Manager;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FTC_Node */
+ /* */
+ /* <Description> */
+ /* An opaque handle to a cache node object. Each cache node is */
+ /* reference-counted. A node with a count of~0 might be flushed */
+ /* out of a full cache whenever a lookup request is performed. */
+ /* */
+ /* If you lookup nodes, you have the ability to `acquire' them, i.e., */
+ /* to increment their reference count. This will prevent the node */
+ /* from being flushed out of the cache until you explicitly `release' */
+ /* it (see @FTC_Node_Unref). */
+ /* */
+ /* See also @FTC_SBitCache_Lookup and @FTC_ImageCache_Lookup. */
+ /* */
+ typedef struct FTC_NodeRec_* FTC_Node;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_Manager_New */
+ /* */
+ /* <Description> */
+ /* Create a new cache manager. */
+ /* */
+ /* <Input> */
+ /* library :: The parent FreeType library handle to use. */
+ /* */
+ /* max_faces :: Maximum number of opened @FT_Face objects managed by */
+ /* this cache instance. Use~0 for defaults. */
+ /* */
+ /* max_sizes :: Maximum number of opened @FT_Size objects managed by */
+ /* this cache instance. Use~0 for defaults. */
+ /* */
+ /* max_bytes :: Maximum number of bytes to use for cached data nodes. */
+ /* Use~0 for defaults. Note that this value does not */
+ /* account for managed @FT_Face and @FT_Size objects. */
+ /* */
+ /* requester :: An application-provided callback used to translate */
+ /* face IDs into real @FT_Face objects. */
+ /* */
+ /* req_data :: A generic pointer that is passed to the requester */
+ /* each time it is called (see @FTC_Face_Requester). */
+ /* */
+ /* <Output> */
+ /* amanager :: A handle to a new manager object. 0~in case of */
+ /* failure. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_Manager_New( FT_Library library,
+ FT_UInt max_faces,
+ FT_UInt max_sizes,
+ FT_ULong max_bytes,
+ FTC_Face_Requester requester,
+ FT_Pointer req_data,
+ FTC_Manager *amanager );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_Manager_Reset */
+ /* */
+ /* <Description> */
+ /* Empty a given cache manager. This simply gets rid of all the */
+ /* currently cached @FT_Face and @FT_Size objects within the manager. */
+ /* */
+ /* <InOut> */
+ /* manager :: A handle to the manager. */
+ /* */
+ FT_EXPORT( void )
+ FTC_Manager_Reset( FTC_Manager manager );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_Manager_Done */
+ /* */
+ /* <Description> */
+ /* Destroy a given manager after emptying it. */
+ /* */
+ /* <Input> */
+ /* manager :: A handle to the target cache manager object. */
+ /* */
+ FT_EXPORT( void )
+ FTC_Manager_Done( FTC_Manager manager );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_Manager_LookupFace */
+ /* */
+ /* <Description> */
+ /* Retrieve the @FT_Face object that corresponds to a given face ID */
+ /* through a cache manager. */
+ /* */
+ /* <Input> */
+ /* manager :: A handle to the cache manager. */
+ /* */
+ /* face_id :: The ID of the face object. */
+ /* */
+ /* <Output> */
+ /* aface :: A handle to the face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* The returned @FT_Face object is always owned by the manager. You */
+ /* should never try to discard it yourself. */
+ /* */
+ /* The @FT_Face object doesn't necessarily have a current size object */
+ /* (i.e., face->size can be 0). If you need a specific `font size', */
+ /* use @FTC_Manager_LookupSize instead. */
+ /* */
+ /* Never change the face's transformation matrix (i.e., never call */
+ /* the @FT_Set_Transform function) on a returned face! If you need */
+ /* to transform glyphs, do it yourself after glyph loading. */
+ /* */
+ /* When you perform a lookup, out-of-memory errors are detected */
+ /* _within_ the lookup and force incremental flushes of the cache */
+ /* until enough memory is released for the lookup to succeed. */
+ /* */
+ /* If a lookup fails with `FT_Err_Out_Of_Memory' the cache has */
+ /* already been completely flushed, and still no memory was available */
+ /* for the operation. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_Manager_LookupFace( FTC_Manager manager,
+ FTC_FaceID face_id,
+ FT_Face *aface );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FTC_ScalerRec */
+ /* */
+ /* <Description> */
+ /* A structure used to describe a given character size in either */
+ /* pixels or points to the cache manager. See */
+ /* @FTC_Manager_LookupSize. */
+ /* */
+ /* <Fields> */
+ /* face_id :: The source face ID. */
+ /* */
+ /* width :: The character width. */
+ /* */
+ /* height :: The character height. */
+ /* */
+ /* pixel :: A Boolean. If 1, the `width' and `height' fields are */
+ /* interpreted as integer pixel character sizes. */
+ /* Otherwise, they are expressed as 1/64th of points. */
+ /* */
+ /* x_res :: Only used when `pixel' is value~0 to indicate the */
+ /* horizontal resolution in dpi. */
+ /* */
+ /* y_res :: Only used when `pixel' is value~0 to indicate the */
+ /* vertical resolution in dpi. */
+ /* */
+ /* <Note> */
+ /* This type is mainly used to retrieve @FT_Size objects through the */
+ /* cache manager. */
+ /* */
+ typedef struct FTC_ScalerRec_
+ {
+ FTC_FaceID face_id;
+ FT_UInt width;
+ FT_UInt height;
+ FT_Int pixel;
+ FT_UInt x_res;
+ FT_UInt y_res;
+
+ } FTC_ScalerRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FTC_Scaler */
+ /* */
+ /* <Description> */
+ /* A handle to an @FTC_ScalerRec structure. */
+ /* */
+ typedef struct FTC_ScalerRec_* FTC_Scaler;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_Manager_LookupSize */
+ /* */
+ /* <Description> */
+ /* Retrieve the @FT_Size object that corresponds to a given */
+ /* @FTC_ScalerRec pointer through a cache manager. */
+ /* */
+ /* <Input> */
+ /* manager :: A handle to the cache manager. */
+ /* */
+ /* scaler :: A scaler handle. */
+ /* */
+ /* <Output> */
+ /* asize :: A handle to the size object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* The returned @FT_Size object is always owned by the manager. You */
+ /* should never try to discard it by yourself. */
+ /* */
+ /* You can access the parent @FT_Face object simply as `size->face' */
+ /* if you need it. Note that this object is also owned by the */
+ /* manager. */
+ /* */
+ /* <Note> */
+ /* When you perform a lookup, out-of-memory errors are detected */
+ /* _within_ the lookup and force incremental flushes of the cache */
+ /* until enough memory is released for the lookup to succeed. */
+ /* */
+ /* If a lookup fails with `FT_Err_Out_Of_Memory' the cache has */
+ /* already been completely flushed, and still no memory is available */
+ /* for the operation. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_Manager_LookupSize( FTC_Manager manager,
+ FTC_Scaler scaler,
+ FT_Size *asize );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_Node_Unref */
+ /* */
+ /* <Description> */
+ /* Decrement a cache node's internal reference count. When the count */
+ /* reaches 0, it is not destroyed but becomes eligible for subsequent */
+ /* cache flushes. */
+ /* */
+ /* <Input> */
+ /* node :: The cache node handle. */
+ /* */
+ /* manager :: The cache manager handle. */
+ /* */
+ FT_EXPORT( void )
+ FTC_Node_Unref( FTC_Node node,
+ FTC_Manager manager );
+
+
+ /*************************************************************************
+ *
+ * @function:
+ * FTC_Manager_RemoveFaceID
+ *
+ * @description:
+ * A special function used to indicate to the cache manager that
+ * a given @FTC_FaceID is no longer valid, either because its
+ * content changed, or because it was deallocated or uninstalled.
+ *
+ * @input:
+ * manager ::
+ * The cache manager handle.
+ *
+ * face_id ::
+ * The @FTC_FaceID to be removed.
+ *
+ * @note:
+ * This function flushes all nodes from the cache corresponding to this
+ * `face_id', with the exception of nodes with a non-null reference
+ * count.
+ *
+ * Such nodes are however modified internally so as to never appear
+ * in later lookups with the same `face_id' value, and to be immediately
+ * destroyed when released by all their users.
+ *
+ */
+ FT_EXPORT( void )
+ FTC_Manager_RemoveFaceID( FTC_Manager manager,
+ FTC_FaceID face_id );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* cache_subsystem */
+ /* */
+ /*************************************************************************/
+
+ /*************************************************************************
+ *
+ * @type:
+ * FTC_CMapCache
+ *
+ * @description:
+ * An opaque handle used to model a charmap cache. This cache is to
+ * hold character codes -> glyph indices mappings.
+ *
+ */
+ typedef struct FTC_CMapCacheRec_* FTC_CMapCache;
+
+
+ /*************************************************************************
+ *
+ * @function:
+ * FTC_CMapCache_New
+ *
+ * @description:
+ * Create a new charmap cache.
+ *
+ * @input:
+ * manager ::
+ * A handle to the cache manager.
+ *
+ * @output:
+ * acache ::
+ * A new cache handle. NULL in case of error.
+ *
+ * @return:
+ * FreeType error code. 0~means success.
+ *
+ * @note:
+ * Like all other caches, this one will be destroyed with the cache
+ * manager.
+ *
+ */
+ FT_EXPORT( FT_Error )
+ FTC_CMapCache_New( FTC_Manager manager,
+ FTC_CMapCache *acache );
+
+
+ /************************************************************************
+ *
+ * @function:
+ * FTC_CMapCache_Lookup
+ *
+ * @description:
+ * Translate a character code into a glyph index, using the charmap
+ * cache.
+ *
+ * @input:
+ * cache ::
+ * A charmap cache handle.
+ *
+ * face_id ::
+ * The source face ID.
+ *
+ * cmap_index ::
+ * The index of the charmap in the source face. Any negative value
+ * means to use the cache @FT_Face's default charmap.
+ *
+ * char_code ::
+ * The character code (in the corresponding charmap).
+ *
+ * @return:
+ * Glyph index. 0~means `no glyph'.
+ *
+ */
+ FT_EXPORT( FT_UInt )
+ FTC_CMapCache_Lookup( FTC_CMapCache cache,
+ FTC_FaceID face_id,
+ FT_Int cmap_index,
+ FT_UInt32 char_code );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* cache_subsystem */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** IMAGE CACHE OBJECT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************
+ *
+ * @struct:
+ * FTC_ImageTypeRec
+ *
+ * @description:
+ * A structure used to model the type of images in a glyph cache.
+ *
+ * @fields:
+ * face_id ::
+ * The face ID.
+ *
+ * width ::
+ * The width in pixels.
+ *
+ * height ::
+ * The height in pixels.
+ *
+ * flags ::
+ * The load flags, as in @FT_Load_Glyph.
+ *
+ */
+ typedef struct FTC_ImageTypeRec_
+ {
+ FTC_FaceID face_id;
+ FT_Int width;
+ FT_Int height;
+ FT_Int32 flags;
+
+ } FTC_ImageTypeRec;
+
+
+ /*************************************************************************
+ *
+ * @type:
+ * FTC_ImageType
+ *
+ * @description:
+ * A handle to an @FTC_ImageTypeRec structure.
+ *
+ */
+ typedef struct FTC_ImageTypeRec_* FTC_ImageType;
+
+
+ /* */
+
+
+#define FTC_IMAGE_TYPE_COMPARE( d1, d2 ) \
+ ( (d1)->face_id == (d2)->face_id && \
+ (d1)->width == (d2)->width && \
+ (d1)->flags == (d2)->flags )
+
+#define FTC_IMAGE_TYPE_HASH( d ) \
+ (FT_UFast)( FTC_FACE_ID_HASH( (d)->face_id ) ^ \
+ ( (d)->width << 8 ) ^ (d)->height ^ \
+ ( (d)->flags << 4 ) )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FTC_ImageCache */
+ /* */
+ /* <Description> */
+ /* A handle to an glyph image cache object. They are designed to */
+ /* hold many distinct glyph images while not exceeding a certain */
+ /* memory threshold. */
+ /* */
+ typedef struct FTC_ImageCacheRec_* FTC_ImageCache;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_ImageCache_New */
+ /* */
+ /* <Description> */
+ /* Create a new glyph image cache. */
+ /* */
+ /* <Input> */
+ /* manager :: The parent manager for the image cache. */
+ /* */
+ /* <Output> */
+ /* acache :: A handle to the new glyph image cache object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_ImageCache_New( FTC_Manager manager,
+ FTC_ImageCache *acache );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_ImageCache_Lookup */
+ /* */
+ /* <Description> */
+ /* Retrieve a given glyph image from a glyph image cache. */
+ /* */
+ /* <Input> */
+ /* cache :: A handle to the source glyph image cache. */
+ /* */
+ /* type :: A pointer to a glyph image type descriptor. */
+ /* */
+ /* gindex :: The glyph index to retrieve. */
+ /* */
+ /* <Output> */
+ /* aglyph :: The corresponding @FT_Glyph object. 0~in case of */
+ /* failure. */
+ /* */
+ /* anode :: Used to return the address of of the corresponding cache */
+ /* node after incrementing its reference count (see note */
+ /* below). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* The returned glyph is owned and managed by the glyph image cache. */
+ /* Never try to transform or discard it manually! You can however */
+ /* create a copy with @FT_Glyph_Copy and modify the new one. */
+ /* */
+ /* If `anode' is _not_ NULL, it receives the address of the cache */
+ /* node containing the glyph image, after increasing its reference */
+ /* count. This ensures that the node (as well as the @FT_Glyph) will */
+ /* always be kept in the cache until you call @FTC_Node_Unref to */
+ /* `release' it. */
+ /* */
+ /* If `anode' is NULL, the cache node is left unchanged, which means */
+ /* that the @FT_Glyph could be flushed out of the cache on the next */
+ /* call to one of the caching sub-system APIs. Don't assume that it */
+ /* is persistent! */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_ImageCache_Lookup( FTC_ImageCache cache,
+ FTC_ImageType type,
+ FT_UInt gindex,
+ FT_Glyph *aglyph,
+ FTC_Node *anode );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_ImageCache_LookupScaler */
+ /* */
+ /* <Description> */
+ /* A variant of @FTC_ImageCache_Lookup that uses an @FTC_ScalerRec */
+ /* to specify the face ID and its size. */
+ /* */
+ /* <Input> */
+ /* cache :: A handle to the source glyph image cache. */
+ /* */
+ /* scaler :: A pointer to a scaler descriptor. */
+ /* */
+ /* load_flags :: The corresponding load flags. */
+ /* */
+ /* gindex :: The glyph index to retrieve. */
+ /* */
+ /* <Output> */
+ /* aglyph :: The corresponding @FT_Glyph object. 0~in case of */
+ /* failure. */
+ /* */
+ /* anode :: Used to return the address of of the corresponding */
+ /* cache node after incrementing its reference count */
+ /* (see note below). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* The returned glyph is owned and managed by the glyph image cache. */
+ /* Never try to transform or discard it manually! You can however */
+ /* create a copy with @FT_Glyph_Copy and modify the new one. */
+ /* */
+ /* If `anode' is _not_ NULL, it receives the address of the cache */
+ /* node containing the glyph image, after increasing its reference */
+ /* count. This ensures that the node (as well as the @FT_Glyph) will */
+ /* always be kept in the cache until you call @FTC_Node_Unref to */
+ /* `release' it. */
+ /* */
+ /* If `anode' is NULL, the cache node is left unchanged, which means */
+ /* that the @FT_Glyph could be flushed out of the cache on the next */
+ /* call to one of the caching sub-system APIs. Don't assume that it */
+ /* is persistent! */
+ /* */
+ /* Calls to @FT_Set_Char_Size and friends have no effect on cached */
+ /* glyphs; you should always use the FreeType cache API instead. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_ImageCache_LookupScaler( FTC_ImageCache cache,
+ FTC_Scaler scaler,
+ FT_ULong load_flags,
+ FT_UInt gindex,
+ FT_Glyph *aglyph,
+ FTC_Node *anode );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FTC_SBit */
+ /* */
+ /* <Description> */
+ /* A handle to a small bitmap descriptor. See the @FTC_SBitRec */
+ /* structure for details. */
+ /* */
+ typedef struct FTC_SBitRec_* FTC_SBit;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FTC_SBitRec */
+ /* */
+ /* <Description> */
+ /* A very compact structure used to describe a small glyph bitmap. */
+ /* */
+ /* <Fields> */
+ /* width :: The bitmap width in pixels. */
+ /* */
+ /* height :: The bitmap height in pixels. */
+ /* */
+ /* left :: The horizontal distance from the pen position to the */
+ /* left bitmap border (a.k.a. `left side bearing', or */
+ /* `lsb'). */
+ /* */
+ /* top :: The vertical distance from the pen position (on the */
+ /* baseline) to the upper bitmap border (a.k.a. `top */
+ /* side bearing'). The distance is positive for upwards */
+ /* y~coordinates. */
+ /* */
+ /* format :: The format of the glyph bitmap (monochrome or gray). */
+ /* */
+ /* max_grays :: Maximum gray level value (in the range 1 to~255). */
+ /* */
+ /* pitch :: The number of bytes per bitmap line. May be positive */
+ /* or negative. */
+ /* */
+ /* xadvance :: The horizontal advance width in pixels. */
+ /* */
+ /* yadvance :: The vertical advance height in pixels. */
+ /* */
+ /* buffer :: A pointer to the bitmap pixels. */
+ /* */
+ typedef struct FTC_SBitRec_
+ {
+ FT_Byte width;
+ FT_Byte height;
+ FT_Char left;
+ FT_Char top;
+
+ FT_Byte format;
+ FT_Byte max_grays;
+ FT_Short pitch;
+ FT_Char xadvance;
+ FT_Char yadvance;
+
+ FT_Byte* buffer;
+
+ } FTC_SBitRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FTC_SBitCache */
+ /* */
+ /* <Description> */
+ /* A handle to a small bitmap cache. These are special cache objects */
+ /* used to store small glyph bitmaps (and anti-aliased pixmaps) in a */
+ /* much more efficient way than the traditional glyph image cache */
+ /* implemented by @FTC_ImageCache. */
+ /* */
+ typedef struct FTC_SBitCacheRec_* FTC_SBitCache;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_SBitCache_New */
+ /* */
+ /* <Description> */
+ /* Create a new cache to store small glyph bitmaps. */
+ /* */
+ /* <Input> */
+ /* manager :: A handle to the source cache manager. */
+ /* */
+ /* <Output> */
+ /* acache :: A handle to the new sbit cache. NULL in case of error. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_SBitCache_New( FTC_Manager manager,
+ FTC_SBitCache *acache );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_SBitCache_Lookup */
+ /* */
+ /* <Description> */
+ /* Look up a given small glyph bitmap in a given sbit cache and */
+ /* `lock' it to prevent its flushing from the cache until needed. */
+ /* */
+ /* <Input> */
+ /* cache :: A handle to the source sbit cache. */
+ /* */
+ /* type :: A pointer to the glyph image type descriptor. */
+ /* */
+ /* gindex :: The glyph index. */
+ /* */
+ /* <Output> */
+ /* sbit :: A handle to a small bitmap descriptor. */
+ /* */
+ /* anode :: Used to return the address of of the corresponding cache */
+ /* node after incrementing its reference count (see note */
+ /* below). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* The small bitmap descriptor and its bit buffer are owned by the */
+ /* cache and should never be freed by the application. They might */
+ /* as well disappear from memory on the next cache lookup, so don't */
+ /* treat them as persistent data. */
+ /* */
+ /* The descriptor's `buffer' field is set to~0 to indicate a missing */
+ /* glyph bitmap. */
+ /* */
+ /* If `anode' is _not_ NULL, it receives the address of the cache */
+ /* node containing the bitmap, after increasing its reference count. */
+ /* This ensures that the node (as well as the image) will always be */
+ /* kept in the cache until you call @FTC_Node_Unref to `release' it. */
+ /* */
+ /* If `anode' is NULL, the cache node is left unchanged, which means */
+ /* that the bitmap could be flushed out of the cache on the next */
+ /* call to one of the caching sub-system APIs. Don't assume that it */
+ /* is persistent! */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_SBitCache_Lookup( FTC_SBitCache cache,
+ FTC_ImageType type,
+ FT_UInt gindex,
+ FTC_SBit *sbit,
+ FTC_Node *anode );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_SBitCache_LookupScaler */
+ /* */
+ /* <Description> */
+ /* A variant of @FTC_SBitCache_Lookup that uses an @FTC_ScalerRec */
+ /* to specify the face ID and its size. */
+ /* */
+ /* <Input> */
+ /* cache :: A handle to the source sbit cache. */
+ /* */
+ /* scaler :: A pointer to the scaler descriptor. */
+ /* */
+ /* load_flags :: The corresponding load flags. */
+ /* */
+ /* gindex :: The glyph index. */
+ /* */
+ /* <Output> */
+ /* sbit :: A handle to a small bitmap descriptor. */
+ /* */
+ /* anode :: Used to return the address of of the corresponding */
+ /* cache node after incrementing its reference count */
+ /* (see note below). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* The small bitmap descriptor and its bit buffer are owned by the */
+ /* cache and should never be freed by the application. They might */
+ /* as well disappear from memory on the next cache lookup, so don't */
+ /* treat them as persistent data. */
+ /* */
+ /* The descriptor's `buffer' field is set to~0 to indicate a missing */
+ /* glyph bitmap. */
+ /* */
+ /* If `anode' is _not_ NULL, it receives the address of the cache */
+ /* node containing the bitmap, after increasing its reference count. */
+ /* This ensures that the node (as well as the image) will always be */
+ /* kept in the cache until you call @FTC_Node_Unref to `release' it. */
+ /* */
+ /* If `anode' is NULL, the cache node is left unchanged, which means */
+ /* that the bitmap could be flushed out of the cache on the next */
+ /* call to one of the caching sub-system APIs. Don't assume that it */
+ /* is persistent! */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_SBitCache_LookupScaler( FTC_SBitCache cache,
+ FTC_Scaler scaler,
+ FT_ULong load_flags,
+ FT_UInt gindex,
+ FTC_SBit *sbit,
+ FTC_Node *anode );
+
+
+ /* */
+
+#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+
+ /*@***********************************************************************/
+ /* */
+ /* <Struct> */
+ /* FTC_FontRec */
+ /* */
+ /* <Description> */
+ /* A simple structure used to describe a given `font' to the cache */
+ /* manager. Note that a `font' is the combination of a given face */
+ /* with a given character size. */
+ /* */
+ /* <Fields> */
+ /* face_id :: The ID of the face to use. */
+ /* */
+ /* pix_width :: The character width in integer pixels. */
+ /* */
+ /* pix_height :: The character height in integer pixels. */
+ /* */
+ typedef struct FTC_FontRec_
+ {
+ FTC_FaceID face_id;
+ FT_UShort pix_width;
+ FT_UShort pix_height;
+
+ } FTC_FontRec;
+
+
+ /* */
+
+
+#define FTC_FONT_COMPARE( f1, f2 ) \
+ ( (f1)->face_id == (f2)->face_id && \
+ (f1)->pix_width == (f2)->pix_width && \
+ (f1)->pix_height == (f2)->pix_height )
+
+#define FTC_FONT_HASH( f ) \
+ (FT_UInt32)( FTC_FACE_ID_HASH((f)->face_id) ^ \
+ ((f)->pix_width << 8) ^ \
+ ((f)->pix_height) )
+
+ typedef FTC_FontRec* FTC_Font;
+
+
+ FT_EXPORT( FT_Error )
+ FTC_Manager_Lookup_Face( FTC_Manager manager,
+ FTC_FaceID face_id,
+ FT_Face *aface );
+
+ FT_EXPORT( FT_Error )
+ FTC_Manager_Lookup_Size( FTC_Manager manager,
+ FTC_Font font,
+ FT_Face *aface,
+ FT_Size *asize );
+
+#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
+
+
+ /* */
+
+FT_END_HEADER
+
+#endif /* __FTCACHE_H__ */
+
+
+/* END */
diff --git a/guilib/freetype2/include/freetype/fterrdef.h b/guilib/freetype2/include/freetype/fterrdef.h
new file mode 100644
index 0000000000..d7ad256bdb
--- /dev/null
+++ b/guilib/freetype2/include/freetype/fterrdef.h
@@ -0,0 +1,239 @@
+/***************************************************************************/
+/* */
+/* fterrdef.h */
+/* */
+/* FreeType error codes (specification). */
+/* */
+/* Copyright 2002, 2004, 2006, 2007 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /***** *****/
+ /***** LIST OF ERROR CODES/MESSAGES *****/
+ /***** *****/
+ /*******************************************************************/
+ /*******************************************************************/
+
+
+ /* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */
+ /* including this file. */
+
+
+ /* generic errors */
+
+ FT_NOERRORDEF_( Ok, 0x00, \
+ "no error" )
+
+ FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \
+ "cannot open resource" )
+ FT_ERRORDEF_( Unknown_File_Format, 0x02, \
+ "unknown file format" )
+ FT_ERRORDEF_( Invalid_File_Format, 0x03, \
+ "broken file" )
+ FT_ERRORDEF_( Invalid_Version, 0x04, \
+ "invalid FreeType version" )
+ FT_ERRORDEF_( Lower_Module_Version, 0x05, \
+ "module version is too low" )
+ FT_ERRORDEF_( Invalid_Argument, 0x06, \
+ "invalid argument" )
+ FT_ERRORDEF_( Unimplemented_Feature, 0x07, \
+ "unimplemented feature" )
+ FT_ERRORDEF_( Invalid_Table, 0x08, \
+ "broken table" )
+ FT_ERRORDEF_( Invalid_Offset, 0x09, \
+ "broken offset within table" )
+ FT_ERRORDEF_( Array_Too_Large, 0x0A, \
+ "array allocation size too large" )
+
+ /* glyph/character errors */
+
+ FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \
+ "invalid glyph index" )
+ FT_ERRORDEF_( Invalid_Character_Code, 0x11, \
+ "invalid character code" )
+ FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \
+ "unsupported glyph image format" )
+ FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \
+ "cannot render this glyph format" )
+ FT_ERRORDEF_( Invalid_Outline, 0x14, \
+ "invalid outline" )
+ FT_ERRORDEF_( Invalid_Composite, 0x15, \
+ "invalid composite glyph" )
+ FT_ERRORDEF_( Too_Many_Hints, 0x16, \
+ "too many hints" )
+ FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \
+ "invalid pixel size" )
+
+ /* handle errors */
+
+ FT_ERRORDEF_( Invalid_Handle, 0x20, \
+ "invalid object handle" )
+ FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \
+ "invalid library handle" )
+ FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \
+ "invalid module handle" )
+ FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \
+ "invalid face handle" )
+ FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \
+ "invalid size handle" )
+ FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \
+ "invalid glyph slot handle" )
+ FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \
+ "invalid charmap handle" )
+ FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \
+ "invalid cache manager handle" )
+ FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \
+ "invalid stream handle" )
+
+ /* driver errors */
+
+ FT_ERRORDEF_( Too_Many_Drivers, 0x30, \
+ "too many modules" )
+ FT_ERRORDEF_( Too_Many_Extensions, 0x31, \
+ "too many extensions" )
+
+ /* memory errors */
+
+ FT_ERRORDEF_( Out_Of_Memory, 0x40, \
+ "out of memory" )
+ FT_ERRORDEF_( Unlisted_Object, 0x41, \
+ "unlisted object" )
+
+ /* stream errors */
+
+ FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \
+ "cannot open stream" )
+ FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \
+ "invalid stream seek" )
+ FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \
+ "invalid stream skip" )
+ FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \
+ "invalid stream read" )
+ FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \
+ "invalid stream operation" )
+ FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \
+ "invalid frame operation" )
+ FT_ERRORDEF_( Nested_Frame_Access, 0x57, \
+ "nested frame access" )
+ FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \
+ "invalid frame read" )
+
+ /* raster errors */
+
+ FT_ERRORDEF_( Raster_Uninitialized, 0x60, \
+ "raster uninitialized" )
+ FT_ERRORDEF_( Raster_Corrupted, 0x61, \
+ "raster corrupted" )
+ FT_ERRORDEF_( Raster_Overflow, 0x62, \
+ "raster overflow" )
+ FT_ERRORDEF_( Raster_Negative_Height, 0x63, \
+ "negative height while rastering" )
+
+ /* cache errors */
+
+ FT_ERRORDEF_( Too_Many_Caches, 0x70, \
+ "too many registered caches" )
+
+ /* TrueType and SFNT errors */
+
+ FT_ERRORDEF_( Invalid_Opcode, 0x80, \
+ "invalid opcode" )
+ FT_ERRORDEF_( Too_Few_Arguments, 0x81, \
+ "too few arguments" )
+ FT_ERRORDEF_( Stack_Overflow, 0x82, \
+ "stack overflow" )
+ FT_ERRORDEF_( Code_Overflow, 0x83, \
+ "code overflow" )
+ FT_ERRORDEF_( Bad_Argument, 0x84, \
+ "bad argument" )
+ FT_ERRORDEF_( Divide_By_Zero, 0x85, \
+ "division by zero" )
+ FT_ERRORDEF_( Invalid_Reference, 0x86, \
+ "invalid reference" )
+ FT_ERRORDEF_( Debug_OpCode, 0x87, \
+ "found debug opcode" )
+ FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \
+ "found ENDF opcode in execution stream" )
+ FT_ERRORDEF_( Nested_DEFS, 0x89, \
+ "nested DEFS" )
+ FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \
+ "invalid code range" )
+ FT_ERRORDEF_( Execution_Too_Long, 0x8B, \
+ "execution context too long" )
+ FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \
+ "too many function definitions" )
+ FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \
+ "too many instruction definitions" )
+ FT_ERRORDEF_( Table_Missing, 0x8E, \
+ "SFNT font table missing" )
+ FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \
+ "horizontal header (hhea) table missing" )
+ FT_ERRORDEF_( Locations_Missing, 0x90, \
+ "locations (loca) table missing" )
+ FT_ERRORDEF_( Name_Table_Missing, 0x91, \
+ "name table missing" )
+ FT_ERRORDEF_( CMap_Table_Missing, 0x92, \
+ "character map (cmap) table missing" )
+ FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \
+ "horizontal metrics (hmtx) table missing" )
+ FT_ERRORDEF_( Post_Table_Missing, 0x94, \
+ "PostScript (post) table missing" )
+ FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \
+ "invalid horizontal metrics" )
+ FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \
+ "invalid character map (cmap) format" )
+ FT_ERRORDEF_( Invalid_PPem, 0x97, \
+ "invalid ppem value" )
+ FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \
+ "invalid vertical metrics" )
+ FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \
+ "could not find context" )
+ FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \
+ "invalid PostScript (post) table format" )
+ FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \
+ "invalid PostScript (post) table" )
+
+ /* CFF, CID, and Type 1 errors */
+
+ FT_ERRORDEF_( Syntax_Error, 0xA0, \
+ "opcode syntax error" )
+ FT_ERRORDEF_( Stack_Underflow, 0xA1, \
+ "argument stack underflow" )
+ FT_ERRORDEF_( Ignore, 0xA2, \
+ "ignore" )
+
+ /* BDF errors */
+
+ FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \
+ "`STARTFONT' field missing" )
+ FT_ERRORDEF_( Missing_Font_Field, 0xB1, \
+ "`FONT' field missing" )
+ FT_ERRORDEF_( Missing_Size_Field, 0xB2, \
+ "`SIZE' field missing" )
+ FT_ERRORDEF_( Missing_Chars_Field, 0xB3, \
+ "`CHARS' field missing" )
+ FT_ERRORDEF_( Missing_Startchar_Field, 0xB4, \
+ "`STARTCHAR' field missing" )
+ FT_ERRORDEF_( Missing_Encoding_Field, 0xB5, \
+ "`ENCODING' field missing" )
+ FT_ERRORDEF_( Missing_Bbx_Field, 0xB6, \
+ "`BBX' field missing" )
+ FT_ERRORDEF_( Bbx_Too_Big, 0xB7, \
+ "`BBX' too big" )
+ FT_ERRORDEF_( Corrupted_Font_Header, 0xB8, \
+ "Font header corrupted or missing fields" )
+ FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xB9, \
+ "Font glyphs corrupted or missing fields" )
+
+
+/* END */
diff --git a/guilib/freetype2/include/freetype/fterrors.h b/guilib/freetype2/include/freetype/fterrors.h
new file mode 100644
index 0000000000..6600dadd0d
--- /dev/null
+++ b/guilib/freetype2/include/freetype/fterrors.h
@@ -0,0 +1,206 @@
+/***************************************************************************/
+/* */
+/* fterrors.h */
+/* */
+/* FreeType error code handling (specification). */
+/* */
+/* Copyright 1996-2001, 2002, 2004, 2007 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This special header file is used to define the handling of FT2 */
+ /* enumeration constants. It can also be used to generate error message */
+ /* strings with a small macro trick explained below. */
+ /* */
+ /* I - Error Formats */
+ /* ----------------- */
+ /* */
+ /* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */
+ /* defined in ftoption.h in order to make the higher byte indicate */
+ /* the module where the error has happened (this is not compatible */
+ /* with standard builds of FreeType 2). You can then use the macro */
+ /* FT_ERROR_BASE macro to extract the generic error code from an */
+ /* FT_Error value. */
+ /* */
+ /* */
+ /* II - Error Message strings */
+ /* -------------------------- */
+ /* */
+ /* The error definitions below are made through special macros that */
+ /* allow client applications to build a table of error message strings */
+ /* if they need it. The strings are not included in a normal build of */
+ /* FreeType 2 to save space (most client applications do not use */
+ /* them). */
+ /* */
+ /* To do so, you have to define the following macros before including */
+ /* this file: */
+ /* */
+ /* FT_ERROR_START_LIST :: */
+ /* This macro is called before anything else to define the start of */
+ /* the error list. It is followed by several FT_ERROR_DEF calls */
+ /* (see below). */
+ /* */
+ /* FT_ERROR_DEF( e, v, s ) :: */
+ /* This macro is called to define one single error. */
+ /* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */
+ /* `v' is the error numerical value. */
+ /* `s' is the corresponding error string. */
+ /* */
+ /* FT_ERROR_END_LIST :: */
+ /* This macro ends the list. */
+ /* */
+ /* Additionally, you have to undefine __FTERRORS_H__ before #including */
+ /* this file. */
+ /* */
+ /* Here is a simple example: */
+ /* */
+ /* { */
+ /* #undef __FTERRORS_H__ */
+ /* #define FT_ERRORDEF( e, v, s ) { e, s }, */
+ /* #define FT_ERROR_START_LIST { */
+ /* #define FT_ERROR_END_LIST { 0, 0 } }; */
+ /* */
+ /* const struct */
+ /* { */
+ /* int err_code; */
+ /* const char* err_msg; */
+ /* } ft_errors[] = */
+ /* */
+ /* #include FT_ERRORS_H */
+ /* } */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTERRORS_H__
+#define __FTERRORS_H__
+
+
+ /* include module base error codes */
+#include FT_MODULE_ERRORS_H
+
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /***** *****/
+ /***** SETUP MACROS *****/
+ /***** *****/
+ /*******************************************************************/
+ /*******************************************************************/
+
+
+#undef FT_NEED_EXTERN_C
+
+#undef FT_ERR_XCAT
+#undef FT_ERR_CAT
+
+#define FT_ERR_XCAT( x, y ) x ## y
+#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y )
+
+
+ /* FT_ERR_PREFIX is used as a prefix for error identifiers. */
+ /* By default, we use `FT_Err_'. */
+ /* */
+#ifndef FT_ERR_PREFIX
+#define FT_ERR_PREFIX FT_Err_
+#endif
+
+
+ /* FT_ERR_BASE is used as the base for module-specific errors. */
+ /* */
+#ifdef FT_CONFIG_OPTION_USE_MODULE_ERRORS
+
+#ifndef FT_ERR_BASE
+#define FT_ERR_BASE FT_Mod_Err_Base
+#endif
+
+#else
+
+#undef FT_ERR_BASE
+#define FT_ERR_BASE 0
+
+#endif /* FT_CONFIG_OPTION_USE_MODULE_ERRORS */
+
+
+ /* If FT_ERRORDEF is not defined, we need to define a simple */
+ /* enumeration type. */
+ /* */
+#ifndef FT_ERRORDEF
+
+#define FT_ERRORDEF( e, v, s ) e = v,
+#define FT_ERROR_START_LIST enum {
+#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) };
+
+#ifdef __cplusplus
+#define FT_NEED_EXTERN_C
+ extern "C" {
+#endif
+
+#endif /* !FT_ERRORDEF */
+
+
+ /* this macro is used to define an error */
+#define FT_ERRORDEF_( e, v, s ) \
+ FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s )
+
+ /* this is only used for <module>_Err_Ok, which must be 0! */
+#define FT_NOERRORDEF_( e, v, s ) \
+ FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s )
+
+
+#ifdef FT_ERROR_START_LIST
+ FT_ERROR_START_LIST
+#endif
+
+
+ /* now include the error codes */
+#include FT_ERROR_DEFINITIONS_H
+
+
+#ifdef FT_ERROR_END_LIST
+ FT_ERROR_END_LIST
+#endif
+
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /***** *****/
+ /***** SIMPLE CLEANUP *****/
+ /***** *****/
+ /*******************************************************************/
+ /*******************************************************************/
+
+#ifdef FT_NEED_EXTERN_C
+ }
+#endif
+
+#undef FT_ERROR_START_LIST
+#undef FT_ERROR_END_LIST
+
+#undef FT_ERRORDEF
+#undef FT_ERRORDEF_
+#undef FT_NOERRORDEF_
+
+#undef FT_NEED_EXTERN_C
+#undef FT_ERR_CONCAT
+#undef FT_ERR_BASE
+
+ /* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */
+#ifndef FT_KEEP_ERR_PREFIX
+#undef FT_ERR_PREFIX
+#endif
+
+#endif /* __FTERRORS_H__ */
+
+
+/* END */
diff --git a/guilib/freetype2/include/freetype/ftglyph.h b/guilib/freetype2/include/freetype/ftglyph.h
new file mode 100644
index 0000000000..cacccf025e
--- /dev/null
+++ b/guilib/freetype2/include/freetype/ftglyph.h
@@ -0,0 +1,613 @@
+/***************************************************************************/
+/* */
+/* ftglyph.h */
+/* */
+/* FreeType convenience functions to handle glyphs (specification). */
+/* */
+/* Copyright 1996-2001, 2002, 2003, 2006, 2008, 2009 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file contains the definition of several convenience functions */
+ /* that can be used by client applications to easily retrieve glyph */
+ /* bitmaps and outlines from a given face. */
+ /* */
+ /* These functions should be optional if you are writing a font server */
+ /* or text layout engine on top of FreeType. However, they are pretty */
+ /* handy for many other simple uses of the library. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTGLYPH_H__
+#define __FTGLYPH_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#ifdef FREETYPE_H
+#error "freetype.h of FreeType 1 has been loaded!"
+#error "Please fix the directory search order for header files"
+#error "so that freetype.h of FreeType 2 is found first."
+#endif
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* glyph_management */
+ /* */
+ /* <Title> */
+ /* Glyph Management */
+ /* */
+ /* <Abstract> */
+ /* Generic interface to manage individual glyph data. */
+ /* */
+ /* <Description> */
+ /* This section contains definitions used to manage glyph data */
+ /* through generic FT_Glyph objects. Each of them can contain a */
+ /* bitmap, a vector outline, or even images in other formats. */
+ /* */
+ /*************************************************************************/
+
+
+ /* forward declaration to a private type */
+ typedef struct FT_Glyph_Class_ FT_Glyph_Class;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Glyph */
+ /* */
+ /* <Description> */
+ /* Handle to an object used to model generic glyph images. It is a */
+ /* pointer to the @FT_GlyphRec structure and can contain a glyph */
+ /* bitmap or pointer. */
+ /* */
+ /* <Note> */
+ /* Glyph objects are not owned by the library. You must thus release */
+ /* them manually (through @FT_Done_Glyph) _before_ calling */
+ /* @FT_Done_FreeType. */
+ /* */
+ typedef struct FT_GlyphRec_* FT_Glyph;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_GlyphRec */
+ /* */
+ /* <Description> */
+ /* The root glyph structure contains a given glyph image plus its */
+ /* advance width in 16.16 fixed float format. */
+ /* */
+ /* <Fields> */
+ /* library :: A handle to the FreeType library object. */
+ /* */
+ /* clazz :: A pointer to the glyph's class. Private. */
+ /* */
+ /* format :: The format of the glyph's image. */
+ /* */
+ /* advance :: A 16.16 vector that gives the glyph's advance width. */
+ /* */
+ typedef struct FT_GlyphRec_
+ {
+ FT_Library library;
+ const FT_Glyph_Class* clazz;
+ FT_Glyph_Format format;
+ FT_Vector advance;
+
+ } FT_GlyphRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_BitmapGlyph */
+ /* */
+ /* <Description> */
+ /* A handle to an object used to model a bitmap glyph image. This is */
+ /* a sub-class of @FT_Glyph, and a pointer to @FT_BitmapGlyphRec. */
+ /* */
+ typedef struct FT_BitmapGlyphRec_* FT_BitmapGlyph;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_BitmapGlyphRec */
+ /* */
+ /* <Description> */
+ /* A structure used for bitmap glyph images. This really is a */
+ /* `sub-class' of @FT_GlyphRec. */
+ /* */
+ /* <Fields> */
+ /* root :: The root @FT_Glyph fields. */
+ /* */
+ /* left :: The left-side bearing, i.e., the horizontal distance */
+ /* from the current pen position to the left border of the */
+ /* glyph bitmap. */
+ /* */
+ /* top :: The top-side bearing, i.e., the vertical distance from */
+ /* the current pen position to the top border of the glyph */
+ /* bitmap. This distance is positive for upwards~y! */
+ /* */
+ /* bitmap :: A descriptor for the bitmap. */
+ /* */
+ /* <Note> */
+ /* You can typecast an @FT_Glyph to @FT_BitmapGlyph if you have */
+ /* `glyph->format == FT_GLYPH_FORMAT_BITMAP'. This lets you access */
+ /* the bitmap's contents easily. */
+ /* */
+ /* The corresponding pixel buffer is always owned by @FT_BitmapGlyph */
+ /* and is thus created and destroyed with it. */
+ /* */
+ typedef struct FT_BitmapGlyphRec_
+ {
+ FT_GlyphRec root;
+ FT_Int left;
+ FT_Int top;
+ FT_Bitmap bitmap;
+
+ } FT_BitmapGlyphRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_OutlineGlyph */
+ /* */
+ /* <Description> */
+ /* A handle to an object used to model an outline glyph image. This */
+ /* is a sub-class of @FT_Glyph, and a pointer to @FT_OutlineGlyphRec. */
+ /* */
+ typedef struct FT_OutlineGlyphRec_* FT_OutlineGlyph;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_OutlineGlyphRec */
+ /* */
+ /* <Description> */
+ /* A structure used for outline (vectorial) glyph images. This */
+ /* really is a `sub-class' of @FT_GlyphRec. */
+ /* */
+ /* <Fields> */
+ /* root :: The root @FT_Glyph fields. */
+ /* */
+ /* outline :: A descriptor for the outline. */
+ /* */
+ /* <Note> */
+ /* You can typecast an @FT_Glyph to @FT_OutlineGlyph if you have */
+ /* `glyph->format == FT_GLYPH_FORMAT_OUTLINE'. This lets you access */
+ /* the outline's content easily. */
+ /* */
+ /* As the outline is extracted from a glyph slot, its coordinates are */
+ /* expressed normally in 26.6 pixels, unless the flag */
+ /* @FT_LOAD_NO_SCALE was used in @FT_Load_Glyph() or @FT_Load_Char(). */
+ /* */
+ /* The outline's tables are always owned by the object and are */
+ /* destroyed with it. */
+ /* */
+ typedef struct FT_OutlineGlyphRec_
+ {
+ FT_GlyphRec root;
+ FT_Outline outline;
+
+ } FT_OutlineGlyphRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Glyph */
+ /* */
+ /* <Description> */
+ /* A function used to extract a glyph image from a slot. Note that */
+ /* the created @FT_Glyph object must be released with @FT_Done_Glyph. */
+ /* */
+ /* <Input> */
+ /* slot :: A handle to the source glyph slot. */
+ /* */
+ /* <Output> */
+ /* aglyph :: A handle to the glyph object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Get_Glyph( FT_GlyphSlot slot,
+ FT_Glyph *aglyph );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Glyph_Copy */
+ /* */
+ /* <Description> */
+ /* A function used to copy a glyph image. Note that the created */
+ /* @FT_Glyph object must be released with @FT_Done_Glyph. */
+ /* */
+ /* <Input> */
+ /* source :: A handle to the source glyph object. */
+ /* */
+ /* <Output> */
+ /* target :: A handle to the target glyph object. 0~in case of */
+ /* error. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Glyph_Copy( FT_Glyph source,
+ FT_Glyph *target );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Glyph_Transform */
+ /* */
+ /* <Description> */
+ /* Transform a glyph image if its format is scalable. */
+ /* */
+ /* <InOut> */
+ /* glyph :: A handle to the target glyph object. */
+ /* */
+ /* <Input> */
+ /* matrix :: A pointer to a 2x2 matrix to apply. */
+ /* */
+ /* delta :: A pointer to a 2d vector to apply. Coordinates are */
+ /* expressed in 1/64th of a pixel. */
+ /* */
+ /* <Return> */
+ /* FreeType error code (if not 0, the glyph format is not scalable). */
+ /* */
+ /* <Note> */
+ /* The 2x2 transformation matrix is also applied to the glyph's */
+ /* advance vector. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Glyph_Transform( FT_Glyph glyph,
+ FT_Matrix* matrix,
+ FT_Vector* delta );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Glyph_BBox_Mode */
+ /* */
+ /* <Description> */
+ /* The mode how the values of @FT_Glyph_Get_CBox are returned. */
+ /* */
+ /* <Values> */
+ /* FT_GLYPH_BBOX_UNSCALED :: */
+ /* Return unscaled font units. */
+ /* */
+ /* FT_GLYPH_BBOX_SUBPIXELS :: */
+ /* Return unfitted 26.6 coordinates. */
+ /* */
+ /* FT_GLYPH_BBOX_GRIDFIT :: */
+ /* Return grid-fitted 26.6 coordinates. */
+ /* */
+ /* FT_GLYPH_BBOX_TRUNCATE :: */
+ /* Return coordinates in integer pixels. */
+ /* */
+ /* FT_GLYPH_BBOX_PIXELS :: */
+ /* Return grid-fitted pixel coordinates. */
+ /* */
+ typedef enum FT_Glyph_BBox_Mode_
+ {
+ FT_GLYPH_BBOX_UNSCALED = 0,
+ FT_GLYPH_BBOX_SUBPIXELS = 0,
+ FT_GLYPH_BBOX_GRIDFIT = 1,
+ FT_GLYPH_BBOX_TRUNCATE = 2,
+ FT_GLYPH_BBOX_PIXELS = 3
+
+ } FT_Glyph_BBox_Mode;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* ft_glyph_bbox_xxx */
+ /* */
+ /* <Description> */
+ /* These constants are deprecated. Use the corresponding */
+ /* @FT_Glyph_BBox_Mode values instead. */
+ /* */
+ /* <Values> */
+ /* ft_glyph_bbox_unscaled :: See @FT_GLYPH_BBOX_UNSCALED. */
+ /* ft_glyph_bbox_subpixels :: See @FT_GLYPH_BBOX_SUBPIXELS. */
+ /* ft_glyph_bbox_gridfit :: See @FT_GLYPH_BBOX_GRIDFIT. */
+ /* ft_glyph_bbox_truncate :: See @FT_GLYPH_BBOX_TRUNCATE. */
+ /* ft_glyph_bbox_pixels :: See @FT_GLYPH_BBOX_PIXELS. */
+ /* */
+#define ft_glyph_bbox_unscaled FT_GLYPH_BBOX_UNSCALED
+#define ft_glyph_bbox_subpixels FT_GLYPH_BBOX_SUBPIXELS
+#define ft_glyph_bbox_gridfit FT_GLYPH_BBOX_GRIDFIT
+#define ft_glyph_bbox_truncate FT_GLYPH_BBOX_TRUNCATE
+#define ft_glyph_bbox_pixels FT_GLYPH_BBOX_PIXELS
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Glyph_Get_CBox */
+ /* */
+ /* <Description> */
+ /* Return a glyph's `control box'. The control box encloses all the */
+ /* outline's points, including Bézier control points. Though it */
+ /* coincides with the exact bounding box for most glyphs, it can be */
+ /* slightly larger in some situations (like when rotating an outline */
+ /* which contains Bézier outside arcs). */
+ /* */
+ /* Computing the control box is very fast, while getting the bounding */
+ /* box can take much more time as it needs to walk over all segments */
+ /* and arcs in the outline. To get the latter, you can use the */
+ /* `ftbbox' component which is dedicated to this single task. */
+ /* */
+ /* <Input> */
+ /* glyph :: A handle to the source glyph object. */
+ /* */
+ /* mode :: The mode which indicates how to interpret the returned */
+ /* bounding box values. */
+ /* */
+ /* <Output> */
+ /* acbox :: The glyph coordinate bounding box. Coordinates are */
+ /* expressed in 1/64th of pixels if it is grid-fitted. */
+ /* */
+ /* <Note> */
+ /* Coordinates are relative to the glyph origin, using the y~upwards */
+ /* convention. */
+ /* */
+ /* If the glyph has been loaded with @FT_LOAD_NO_SCALE, `bbox_mode' */
+ /* must be set to @FT_GLYPH_BBOX_UNSCALED to get unscaled font */
+ /* units in 26.6 pixel format. The value @FT_GLYPH_BBOX_SUBPIXELS */
+ /* is another name for this constant. */
+ /* */
+ /* Note that the maximum coordinates are exclusive, which means that */
+ /* one can compute the width and height of the glyph image (be it in */
+ /* integer or 26.6 pixels) as: */
+ /* */
+ /* { */
+ /* width = bbox.xMax - bbox.xMin; */
+ /* height = bbox.yMax - bbox.yMin; */
+ /* } */
+ /* */
+ /* Note also that for 26.6 coordinates, if `bbox_mode' is set to */
+ /* @FT_GLYPH_BBOX_GRIDFIT, the coordinates will also be grid-fitted, */
+ /* which corresponds to: */
+ /* */
+ /* { */
+ /* bbox.xMin = FLOOR(bbox.xMin); */
+ /* bbox.yMin = FLOOR(bbox.yMin); */
+ /* bbox.xMax = CEILING(bbox.xMax); */
+ /* bbox.yMax = CEILING(bbox.yMax); */
+ /* } */
+ /* */
+ /* To get the bbox in pixel coordinates, set `bbox_mode' to */
+ /* @FT_GLYPH_BBOX_TRUNCATE. */
+ /* */
+ /* To get the bbox in grid-fitted pixel coordinates, set `bbox_mode' */
+ /* to @FT_GLYPH_BBOX_PIXELS. */
+ /* */
+ FT_EXPORT( void )
+ FT_Glyph_Get_CBox( FT_Glyph glyph,
+ FT_UInt bbox_mode,
+ FT_BBox *acbox );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Glyph_To_Bitmap */
+ /* */
+ /* <Description> */
+ /* Convert a given glyph object to a bitmap glyph object. */
+ /* */
+ /* <InOut> */
+ /* the_glyph :: A pointer to a handle to the target glyph. */
+ /* */
+ /* <Input> */
+ /* render_mode :: An enumeration that describes how the data is */
+ /* rendered. */
+ /* */
+ /* origin :: A pointer to a vector used to translate the glyph */
+ /* image before rendering. Can be~0 (if no */
+ /* translation). The origin is expressed in */
+ /* 26.6 pixels. */
+ /* */
+ /* destroy :: A boolean that indicates that the original glyph */
+ /* image should be destroyed by this function. It is */
+ /* never destroyed in case of error. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* This function does nothing if the glyph format isn't scalable. */
+ /* */
+ /* The glyph image is translated with the `origin' vector before */
+ /* rendering. */
+ /* */
+ /* The first parameter is a pointer to an @FT_Glyph handle, that will */
+ /* be _replaced_ by this function (with newly allocated data). */
+ /* Typically, you would use (omitting error handling): */
+ /* */
+ /* */
+ /* { */
+ /* FT_Glyph glyph; */
+ /* FT_BitmapGlyph glyph_bitmap; */
+ /* */
+ /* */
+ /* // load glyph */
+ /* error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAUT ); */
+ /* */
+ /* // extract glyph image */
+ /* error = FT_Get_Glyph( face->glyph, &glyph ); */
+ /* */
+ /* // convert to a bitmap (default render mode + destroying old) */
+ /* if ( glyph->format != FT_GLYPH_FORMAT_BITMAP ) */
+ /* { */
+ /* error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_DEFAULT, */
+ /* 0, 1 ); */
+ /* if ( error ) // `glyph' unchanged */
+ /* ... */
+ /* } */
+ /* */
+ /* // access bitmap content by typecasting */
+ /* glyph_bitmap = (FT_BitmapGlyph)glyph; */
+ /* */
+ /* // do funny stuff with it, like blitting/drawing */
+ /* ... */
+ /* */
+ /* // discard glyph image (bitmap or not) */
+ /* FT_Done_Glyph( glyph ); */
+ /* } */
+ /* */
+ /* */
+ /* Here another example, again without error handling: */
+ /* */
+ /* */
+ /* { */
+ /* FT_Glyph glyphs[MAX_GLYPHS] */
+ /* */
+ /* */
+ /* ... */
+ /* */
+ /* for ( idx = 0; i < MAX_GLYPHS; i++ ) */
+ /* error = FT_Load_Glyph( face, idx, FT_LOAD_DEFAULT ) || */
+ /* FT_Get_Glyph ( face->glyph, &glyph[idx] ); */
+ /* */
+ /* ... */
+ /* */
+ /* for ( idx = 0; i < MAX_GLYPHS; i++ ) */
+ /* { */
+ /* FT_Glyph bitmap = glyphs[idx]; */
+ /* */
+ /* */
+ /* ... */
+ /* */
+ /* // after this call, `bitmap' no longer points into */
+ /* // the `glyphs' array (and the old value isn't destroyed) */
+ /* FT_Glyph_To_Bitmap( &bitmap, FT_RENDER_MODE_MONO, 0, 0 ); */
+ /* */
+ /* ... */
+ /* */
+ /* FT_Done_Glyph( bitmap ); */
+ /* } */
+ /* */
+ /* ... */
+ /* */
+ /* for ( idx = 0; i < MAX_GLYPHS; i++ ) */
+ /* FT_Done_Glyph( glyphs[idx] ); */
+ /* } */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Glyph_To_Bitmap( FT_Glyph* the_glyph,
+ FT_Render_Mode render_mode,
+ FT_Vector* origin,
+ FT_Bool destroy );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Done_Glyph */
+ /* */
+ /* <Description> */
+ /* Destroy a given glyph. */
+ /* */
+ /* <Input> */
+ /* glyph :: A handle to the target glyph object. */
+ /* */
+ FT_EXPORT( void )
+ FT_Done_Glyph( FT_Glyph glyph );
+
+ /* */
+
+
+ /* other helpful functions */
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* computations */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Matrix_Multiply */
+ /* */
+ /* <Description> */
+ /* Perform the matrix operation `b = a*b'. */
+ /* */
+ /* <Input> */
+ /* a :: A pointer to matrix `a'. */
+ /* */
+ /* <InOut> */
+ /* b :: A pointer to matrix `b'. */
+ /* */
+ /* <Note> */
+ /* The result is undefined if either `a' or `b' is zero. */
+ /* */
+ FT_EXPORT( void )
+ FT_Matrix_Multiply( const FT_Matrix* a,
+ FT_Matrix* b );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Matrix_Invert */
+ /* */
+ /* <Description> */
+ /* Invert a 2x2 matrix. Return an error if it can't be inverted. */
+ /* */
+ /* <InOut> */
+ /* matrix :: A pointer to the target matrix. Remains untouched in */
+ /* case of error. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Matrix_Invert( FT_Matrix* matrix );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTGLYPH_H__ */
+
+
+/* END */
+
+
+/* Local Variables: */
+/* coding: utf-8 */
+/* End: */
diff --git a/guilib/freetype2/include/freetype/ftimage.h b/guilib/freetype2/include/freetype/ftimage.h
new file mode 100644
index 0000000000..ccc2f71350
--- /dev/null
+++ b/guilib/freetype2/include/freetype/ftimage.h
@@ -0,0 +1,1254 @@
+/***************************************************************************/
+/* */
+/* ftimage.h */
+/* */
+/* FreeType glyph image formats and default raster interface */
+/* (specification). */
+/* */
+/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* Note: A `raster' is simply a scan-line converter, used to render */
+ /* FT_Outlines into FT_Bitmaps. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTIMAGE_H__
+#define __FTIMAGE_H__
+
+
+ /* _STANDALONE_ is from ftgrays.c */
+#ifndef _STANDALONE_
+#include <ft2build.h>
+#endif
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* basic_types */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Pos */
+ /* */
+ /* <Description> */
+ /* The type FT_Pos is a 32-bit integer used to store vectorial */
+ /* coordinates. Depending on the context, these can represent */
+ /* distances in integer font units, or 16.16, or 26.6 fixed float */
+ /* pixel coordinates. */
+ /* */
+ typedef signed long FT_Pos;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Vector */
+ /* */
+ /* <Description> */
+ /* A simple structure used to store a 2D vector; coordinates are of */
+ /* the FT_Pos type. */
+ /* */
+ /* <Fields> */
+ /* x :: The horizontal coordinate. */
+ /* y :: The vertical coordinate. */
+ /* */
+ typedef struct FT_Vector_
+ {
+ FT_Pos x;
+ FT_Pos y;
+
+ } FT_Vector;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_BBox */
+ /* */
+ /* <Description> */
+ /* A structure used to hold an outline's bounding box, i.e., the */
+ /* coordinates of its extrema in the horizontal and vertical */
+ /* directions. */
+ /* */
+ /* <Fields> */
+ /* xMin :: The horizontal minimum (left-most). */
+ /* */
+ /* yMin :: The vertical minimum (bottom-most). */
+ /* */
+ /* xMax :: The horizontal maximum (right-most). */
+ /* */
+ /* yMax :: The vertical maximum (top-most). */
+ /* */
+ typedef struct FT_BBox_
+ {
+ FT_Pos xMin, yMin;
+ FT_Pos xMax, yMax;
+
+ } FT_BBox;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Pixel_Mode */
+ /* */
+ /* <Description> */
+ /* An enumeration type used to describe the format of pixels in a */
+ /* given bitmap. Note that additional formats may be added in the */
+ /* future. */
+ /* */
+ /* <Values> */
+ /* FT_PIXEL_MODE_NONE :: */
+ /* Value~0 is reserved. */
+ /* */
+ /* FT_PIXEL_MODE_MONO :: */
+ /* A monochrome bitmap, using 1~bit per pixel. Note that pixels */
+ /* are stored in most-significant order (MSB), which means that */
+ /* the left-most pixel in a byte has value 128. */
+ /* */
+ /* FT_PIXEL_MODE_GRAY :: */
+ /* An 8-bit bitmap, generally used to represent anti-aliased glyph */
+ /* images. Each pixel is stored in one byte. Note that the number */
+ /* of `gray' levels is stored in the `num_grays' field of the */
+ /* @FT_Bitmap structure (it generally is 256). */
+ /* */
+ /* FT_PIXEL_MODE_GRAY2 :: */
+ /* A 2-bit per pixel bitmap, used to represent embedded */
+ /* anti-aliased bitmaps in font files according to the OpenType */
+ /* specification. We haven't found a single font using this */
+ /* format, however. */
+ /* */
+ /* FT_PIXEL_MODE_GRAY4 :: */
+ /* A 4-bit per pixel bitmap, representing embedded anti-aliased */
+ /* bitmaps in font files according to the OpenType specification. */
+ /* We haven't found a single font using this format, however. */
+ /* */
+ /* FT_PIXEL_MODE_LCD :: */
+ /* An 8-bit bitmap, representing RGB or BGR decimated glyph images */
+ /* used for display on LCD displays; the bitmap is three times */
+ /* wider than the original glyph image. See also */
+ /* @FT_RENDER_MODE_LCD. */
+ /* */
+ /* FT_PIXEL_MODE_LCD_V :: */
+ /* An 8-bit bitmap, representing RGB or BGR decimated glyph images */
+ /* used for display on rotated LCD displays; the bitmap is three */
+ /* times taller than the original glyph image. See also */
+ /* @FT_RENDER_MODE_LCD_V. */
+ /* */
+ typedef enum FT_Pixel_Mode_
+ {
+ FT_PIXEL_MODE_NONE = 0,
+ FT_PIXEL_MODE_MONO,
+ FT_PIXEL_MODE_GRAY,
+ FT_PIXEL_MODE_GRAY2,
+ FT_PIXEL_MODE_GRAY4,
+ FT_PIXEL_MODE_LCD,
+ FT_PIXEL_MODE_LCD_V,
+
+ FT_PIXEL_MODE_MAX /* do not remove */
+
+ } FT_Pixel_Mode;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* ft_pixel_mode_xxx */
+ /* */
+ /* <Description> */
+ /* A list of deprecated constants. Use the corresponding */
+ /* @FT_Pixel_Mode values instead. */
+ /* */
+ /* <Values> */
+ /* ft_pixel_mode_none :: See @FT_PIXEL_MODE_NONE. */
+ /* ft_pixel_mode_mono :: See @FT_PIXEL_MODE_MONO. */
+ /* ft_pixel_mode_grays :: See @FT_PIXEL_MODE_GRAY. */
+ /* ft_pixel_mode_pal2 :: See @FT_PIXEL_MODE_GRAY2. */
+ /* ft_pixel_mode_pal4 :: See @FT_PIXEL_MODE_GRAY4. */
+ /* */
+#define ft_pixel_mode_none FT_PIXEL_MODE_NONE
+#define ft_pixel_mode_mono FT_PIXEL_MODE_MONO
+#define ft_pixel_mode_grays FT_PIXEL_MODE_GRAY
+#define ft_pixel_mode_pal2 FT_PIXEL_MODE_GRAY2
+#define ft_pixel_mode_pal4 FT_PIXEL_MODE_GRAY4
+
+ /* */
+
+#if 0
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Palette_Mode */
+ /* */
+ /* <Description> */
+ /* THIS TYPE IS DEPRECATED. DO NOT USE IT! */
+ /* */
+ /* An enumeration type to describe the format of a bitmap palette, */
+ /* used with ft_pixel_mode_pal4 and ft_pixel_mode_pal8. */
+ /* */
+ /* <Values> */
+ /* ft_palette_mode_rgb :: The palette is an array of 3-byte RGB */
+ /* records. */
+ /* */
+ /* ft_palette_mode_rgba :: The palette is an array of 4-byte RGBA */
+ /* records. */
+ /* */
+ /* <Note> */
+ /* As ft_pixel_mode_pal2, pal4 and pal8 are currently unused by */
+ /* FreeType, these types are not handled by the library itself. */
+ /* */
+ typedef enum FT_Palette_Mode_
+ {
+ ft_palette_mode_rgb = 0,
+ ft_palette_mode_rgba,
+
+ ft_palette_mode_max /* do not remove */
+
+ } FT_Palette_Mode;
+
+ /* */
+
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Bitmap */
+ /* */
+ /* <Description> */
+ /* A structure used to describe a bitmap or pixmap to the raster. */
+ /* Note that we now manage pixmaps of various depths through the */
+ /* `pixel_mode' field. */
+ /* */
+ /* <Fields> */
+ /* rows :: The number of bitmap rows. */
+ /* */
+ /* width :: The number of pixels in bitmap row. */
+ /* */
+ /* pitch :: The pitch's absolute value is the number of bytes */
+ /* taken by one bitmap row, including padding. */
+ /* However, the pitch is positive when the bitmap has */
+ /* a `down' flow, and negative when it has an `up' */
+ /* flow. In all cases, the pitch is an offset to add */
+ /* to a bitmap pointer in order to go down one row. */
+ /* */
+ /* buffer :: A typeless pointer to the bitmap buffer. This */
+ /* value should be aligned on 32-bit boundaries in */
+ /* most cases. */
+ /* */
+ /* num_grays :: This field is only used with */
+ /* @FT_PIXEL_MODE_GRAY; it gives the number of gray */
+ /* levels used in the bitmap. */
+ /* */
+ /* pixel_mode :: The pixel mode, i.e., how pixel bits are stored. */
+ /* See @FT_Pixel_Mode for possible values. */
+ /* */
+ /* palette_mode :: This field is intended for paletted pixel modes; */
+ /* it indicates how the palette is stored. Not */
+ /* used currently. */
+ /* */
+ /* palette :: A typeless pointer to the bitmap palette; this */
+ /* field is intended for paletted pixel modes. Not */
+ /* used currently. */
+ /* */
+ /* <Note> */
+ /* For now, the only pixel modes supported by FreeType are mono and */
+ /* grays. However, drivers might be added in the future to support */
+ /* more `colorful' options. */
+ /* */
+ typedef struct FT_Bitmap_
+ {
+ int rows;
+ int width;
+ int pitch;
+ unsigned char* buffer;
+ short num_grays;
+ char pixel_mode;
+ char palette_mode;
+ void* palette;
+
+ } FT_Bitmap;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* outline_processing */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Outline */
+ /* */
+ /* <Description> */
+ /* This structure is used to describe an outline to the scan-line */
+ /* converter. */
+ /* */
+ /* <Fields> */
+ /* n_contours :: The number of contours in the outline. */
+ /* */
+ /* n_points :: The number of points in the outline. */
+ /* */
+ /* points :: A pointer to an array of `n_points' @FT_Vector */
+ /* elements, giving the outline's point coordinates. */
+ /* */
+ /* tags :: A pointer to an array of `n_points' chars, giving */
+ /* each outline point's type. If bit~0 is unset, the */
+ /* point is `off' the curve, i.e., a Bézier control */
+ /* point, while it is `on' when set. */
+ /* */
+ /* Bit~1 is meaningful for `off' points only. If set, */
+ /* it indicates a third-order Bézier arc control point; */
+ /* and a second-order control point if unset. */
+ /* */
+ /* contours :: An array of `n_contours' shorts, giving the end */
+ /* point of each contour within the outline. For */
+ /* example, the first contour is defined by the points */
+ /* `0' to `contours[0]', the second one is defined by */
+ /* the points `contours[0]+1' to `contours[1]', etc. */
+ /* */
+ /* flags :: A set of bit flags used to characterize the outline */
+ /* and give hints to the scan-converter and hinter on */
+ /* how to convert/grid-fit it. See @FT_OUTLINE_FLAGS. */
+ /* */
+ typedef struct FT_Outline_
+ {
+ short n_contours; /* number of contours in glyph */
+ short n_points; /* number of points in the glyph */
+
+ FT_Vector* points; /* the outline's points */
+ char* tags; /* the points flags */
+ short* contours; /* the contour end points */
+
+ int flags; /* outline masks */
+
+ } FT_Outline;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_OUTLINE_FLAGS */
+ /* */
+ /* <Description> */
+ /* A list of bit-field constants use for the flags in an outline's */
+ /* `flags' field. */
+ /* */
+ /* <Values> */
+ /* FT_OUTLINE_NONE :: */
+ /* Value~0 is reserved. */
+ /* */
+ /* FT_OUTLINE_OWNER :: */
+ /* If set, this flag indicates that the outline's field arrays */
+ /* (i.e., `points', `flags', and `contours') are `owned' by the */
+ /* outline object, and should thus be freed when it is destroyed. */
+ /* */
+ /* FT_OUTLINE_EVEN_ODD_FILL :: */
+ /* By default, outlines are filled using the non-zero winding rule. */
+ /* If set to 1, the outline will be filled using the even-odd fill */
+ /* rule (only works with the smooth raster). */
+ /* */
+ /* FT_OUTLINE_REVERSE_FILL :: */
+ /* By default, outside contours of an outline are oriented in */
+ /* clock-wise direction, as defined in the TrueType specification. */
+ /* This flag is set if the outline uses the opposite direction */
+ /* (typically for Type~1 fonts). This flag is ignored by the scan */
+ /* converter. */
+ /* */
+ /* FT_OUTLINE_IGNORE_DROPOUTS :: */
+ /* By default, the scan converter will try to detect drop-outs in */
+ /* an outline and correct the glyph bitmap to ensure consistent */
+ /* shape continuity. If set, this flag hints the scan-line */
+ /* converter to ignore such cases. */
+ /* */
+ /* FT_OUTLINE_SMART_DROPOUTS :: */
+ /* Select smart dropout control. If unset, use simple dropout */
+ /* control. Ignored if @FT_OUTLINE_IGNORE_DROPOUTS is set. */
+ /* */
+ /* FT_OUTLINE_INCLUDE_STUBS :: */
+ /* If set, turn pixels on for `stubs', otherwise exclude them. */
+ /* Ignored if @FT_OUTLINE_IGNORE_DROPOUTS is set. */
+ /* */
+ /* FT_OUTLINE_HIGH_PRECISION :: */
+ /* This flag indicates that the scan-line converter should try to */
+ /* convert this outline to bitmaps with the highest possible */
+ /* quality. It is typically set for small character sizes. Note */
+ /* that this is only a hint that might be completely ignored by a */
+ /* given scan-converter. */
+ /* */
+ /* FT_OUTLINE_SINGLE_PASS :: */
+ /* This flag is set to force a given scan-converter to only use a */
+ /* single pass over the outline to render a bitmap glyph image. */
+ /* Normally, it is set for very large character sizes. It is only */
+ /* a hint that might be completely ignored by a given */
+ /* scan-converter. */
+ /* */
+ /* <Note> */
+ /* Please refer to the description of the `SCANTYPE' instruction in */
+ /* the OpenType specification (in file `ttinst1.doc') how simple */
+ /* drop-outs, smart drop-outs, and stubs are defined. */
+ /* */
+#define FT_OUTLINE_NONE 0x0
+#define FT_OUTLINE_OWNER 0x1
+#define FT_OUTLINE_EVEN_ODD_FILL 0x2
+#define FT_OUTLINE_REVERSE_FILL 0x4
+#define FT_OUTLINE_IGNORE_DROPOUTS 0x8
+#define FT_OUTLINE_SMART_DROPOUTS 0x10
+#define FT_OUTLINE_INCLUDE_STUBS 0x20
+
+#define FT_OUTLINE_HIGH_PRECISION 0x100
+#define FT_OUTLINE_SINGLE_PASS 0x200
+
+
+ /*************************************************************************
+ *
+ * @enum:
+ * ft_outline_flags
+ *
+ * @description:
+ * These constants are deprecated. Please use the corresponding
+ * @FT_OUTLINE_FLAGS values.
+ *
+ * @values:
+ * ft_outline_none :: See @FT_OUTLINE_NONE.
+ * ft_outline_owner :: See @FT_OUTLINE_OWNER.
+ * ft_outline_even_odd_fill :: See @FT_OUTLINE_EVEN_ODD_FILL.
+ * ft_outline_reverse_fill :: See @FT_OUTLINE_REVERSE_FILL.
+ * ft_outline_ignore_dropouts :: See @FT_OUTLINE_IGNORE_DROPOUTS.
+ * ft_outline_high_precision :: See @FT_OUTLINE_HIGH_PRECISION.
+ * ft_outline_single_pass :: See @FT_OUTLINE_SINGLE_PASS.
+ */
+#define ft_outline_none FT_OUTLINE_NONE
+#define ft_outline_owner FT_OUTLINE_OWNER
+#define ft_outline_even_odd_fill FT_OUTLINE_EVEN_ODD_FILL
+#define ft_outline_reverse_fill FT_OUTLINE_REVERSE_FILL
+#define ft_outline_ignore_dropouts FT_OUTLINE_IGNORE_DROPOUTS
+#define ft_outline_high_precision FT_OUTLINE_HIGH_PRECISION
+#define ft_outline_single_pass FT_OUTLINE_SINGLE_PASS
+
+ /* */
+
+#define FT_CURVE_TAG( flag ) ( flag & 3 )
+
+#define FT_CURVE_TAG_ON 1
+#define FT_CURVE_TAG_CONIC 0
+#define FT_CURVE_TAG_CUBIC 2
+
+#define FT_CURVE_TAG_TOUCH_X 8 /* reserved for the TrueType hinter */
+#define FT_CURVE_TAG_TOUCH_Y 16 /* reserved for the TrueType hinter */
+
+#define FT_CURVE_TAG_TOUCH_BOTH ( FT_CURVE_TAG_TOUCH_X | \
+ FT_CURVE_TAG_TOUCH_Y )
+
+#define FT_Curve_Tag_On FT_CURVE_TAG_ON
+#define FT_Curve_Tag_Conic FT_CURVE_TAG_CONIC
+#define FT_Curve_Tag_Cubic FT_CURVE_TAG_CUBIC
+#define FT_Curve_Tag_Touch_X FT_CURVE_TAG_TOUCH_X
+#define FT_Curve_Tag_Touch_Y FT_CURVE_TAG_TOUCH_Y
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Outline_MoveToFunc */
+ /* */
+ /* <Description> */
+ /* A function pointer type used to describe the signature of a `move */
+ /* to' function during outline walking/decomposition. */
+ /* */
+ /* A `move to' is emitted to start a new contour in an outline. */
+ /* */
+ /* <Input> */
+ /* to :: A pointer to the target point of the `move to'. */
+ /* */
+ /* user :: A typeless pointer which is passed from the caller of the */
+ /* decomposition function. */
+ /* */
+ /* <Return> */
+ /* Error code. 0~means success. */
+ /* */
+ typedef int
+ (*FT_Outline_MoveToFunc)( const FT_Vector* to,
+ void* user );
+
+#define FT_Outline_MoveTo_Func FT_Outline_MoveToFunc
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Outline_LineToFunc */
+ /* */
+ /* <Description> */
+ /* A function pointer type used to describe the signature of a `line */
+ /* to' function during outline walking/decomposition. */
+ /* */
+ /* A `line to' is emitted to indicate a segment in the outline. */
+ /* */
+ /* <Input> */
+ /* to :: A pointer to the target point of the `line to'. */
+ /* */
+ /* user :: A typeless pointer which is passed from the caller of the */
+ /* decomposition function. */
+ /* */
+ /* <Return> */
+ /* Error code. 0~means success. */
+ /* */
+ typedef int
+ (*FT_Outline_LineToFunc)( const FT_Vector* to,
+ void* user );
+
+#define FT_Outline_LineTo_Func FT_Outline_LineToFunc
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Outline_ConicToFunc */
+ /* */
+ /* <Description> */
+ /* A function pointer type use to describe the signature of a `conic */
+ /* to' function during outline walking/decomposition. */
+ /* */
+ /* A `conic to' is emitted to indicate a second-order Bézier arc in */
+ /* the outline. */
+ /* */
+ /* <Input> */
+ /* control :: An intermediate control point between the last position */
+ /* and the new target in `to'. */
+ /* */
+ /* to :: A pointer to the target end point of the conic arc. */
+ /* */
+ /* user :: A typeless pointer which is passed from the caller of */
+ /* the decomposition function. */
+ /* */
+ /* <Return> */
+ /* Error code. 0~means success. */
+ /* */
+ typedef int
+ (*FT_Outline_ConicToFunc)( const FT_Vector* control,
+ const FT_Vector* to,
+ void* user );
+
+#define FT_Outline_ConicTo_Func FT_Outline_ConicToFunc
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Outline_CubicToFunc */
+ /* */
+ /* <Description> */
+ /* A function pointer type used to describe the signature of a `cubic */
+ /* to' function during outline walking/decomposition. */
+ /* */
+ /* A `cubic to' is emitted to indicate a third-order Bézier arc. */
+ /* */
+ /* <Input> */
+ /* control1 :: A pointer to the first Bézier control point. */
+ /* */
+ /* control2 :: A pointer to the second Bézier control point. */
+ /* */
+ /* to :: A pointer to the target end point. */
+ /* */
+ /* user :: A typeless pointer which is passed from the caller of */
+ /* the decomposition function. */
+ /* */
+ /* <Return> */
+ /* Error code. 0~means success. */
+ /* */
+ typedef int
+ (*FT_Outline_CubicToFunc)( const FT_Vector* control1,
+ const FT_Vector* control2,
+ const FT_Vector* to,
+ void* user );
+
+#define FT_Outline_CubicTo_Func FT_Outline_CubicToFunc
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Outline_Funcs */
+ /* */
+ /* <Description> */
+ /* A structure to hold various function pointers used during outline */
+ /* decomposition in order to emit segments, conic, and cubic Béziers, */
+ /* as well as `move to' and `close to' operations. */
+ /* */
+ /* <Fields> */
+ /* move_to :: The `move to' emitter. */
+ /* */
+ /* line_to :: The segment emitter. */
+ /* */
+ /* conic_to :: The second-order Bézier arc emitter. */
+ /* */
+ /* cubic_to :: The third-order Bézier arc emitter. */
+ /* */
+ /* shift :: The shift that is applied to coordinates before they */
+ /* are sent to the emitter. */
+ /* */
+ /* delta :: The delta that is applied to coordinates before they */
+ /* are sent to the emitter, but after the shift. */
+ /* */
+ /* <Note> */
+ /* The point coordinates sent to the emitters are the transformed */
+ /* version of the original coordinates (this is important for high */
+ /* accuracy during scan-conversion). The transformation is simple: */
+ /* */
+ /* { */
+ /* x' = (x << shift) - delta */
+ /* y' = (x << shift) - delta */
+ /* } */
+ /* */
+ /* Set the value of `shift' and `delta' to~0 to get the original */
+ /* point coordinates. */
+ /* */
+ typedef struct FT_Outline_Funcs_
+ {
+ FT_Outline_MoveToFunc move_to;
+ FT_Outline_LineToFunc line_to;
+ FT_Outline_ConicToFunc conic_to;
+ FT_Outline_CubicToFunc cubic_to;
+
+ int shift;
+ FT_Pos delta;
+
+ } FT_Outline_Funcs;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* basic_types */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Macro> */
+ /* FT_IMAGE_TAG */
+ /* */
+ /* <Description> */
+ /* This macro converts four-letter tags to an unsigned long type. */
+ /* */
+ /* <Note> */
+ /* Since many 16-bit compilers don't like 32-bit enumerations, you */
+ /* should redefine this macro in case of problems to something like */
+ /* this: */
+ /* */
+ /* { */
+ /* #define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) value */
+ /* } */
+ /* */
+ /* to get a simple enumeration without assigning special numbers. */
+ /* */
+#ifndef FT_IMAGE_TAG
+#define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) \
+ value = ( ( (unsigned long)_x1 << 24 ) | \
+ ( (unsigned long)_x2 << 16 ) | \
+ ( (unsigned long)_x3 << 8 ) | \
+ (unsigned long)_x4 )
+#endif /* FT_IMAGE_TAG */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Glyph_Format */
+ /* */
+ /* <Description> */
+ /* An enumeration type used to describe the format of a given glyph */
+ /* image. Note that this version of FreeType only supports two image */
+ /* formats, even though future font drivers will be able to register */
+ /* their own format. */
+ /* */
+ /* <Values> */
+ /* FT_GLYPH_FORMAT_NONE :: */
+ /* The value~0 is reserved. */
+ /* */
+ /* FT_GLYPH_FORMAT_COMPOSITE :: */
+ /* The glyph image is a composite of several other images. This */
+ /* format is _only_ used with @FT_LOAD_NO_RECURSE, and is used to */
+ /* report compound glyphs (like accented characters). */
+ /* */
+ /* FT_GLYPH_FORMAT_BITMAP :: */
+ /* The glyph image is a bitmap, and can be described as an */
+ /* @FT_Bitmap. You generally need to access the `bitmap' field of */
+ /* the @FT_GlyphSlotRec structure to read it. */
+ /* */
+ /* FT_GLYPH_FORMAT_OUTLINE :: */
+ /* The glyph image is a vectorial outline made of line segments */
+ /* and Bézier arcs; it can be described as an @FT_Outline; you */
+ /* generally want to access the `outline' field of the */
+ /* @FT_GlyphSlotRec structure to read it. */
+ /* */
+ /* FT_GLYPH_FORMAT_PLOTTER :: */
+ /* The glyph image is a vectorial path with no inside and outside */
+ /* contours. Some Type~1 fonts, like those in the Hershey family, */
+ /* contain glyphs in this format. These are described as */
+ /* @FT_Outline, but FreeType isn't currently capable of rendering */
+ /* them correctly. */
+ /* */
+ typedef enum FT_Glyph_Format_
+ {
+ FT_IMAGE_TAG( FT_GLYPH_FORMAT_NONE, 0, 0, 0, 0 ),
+
+ FT_IMAGE_TAG( FT_GLYPH_FORMAT_COMPOSITE, 'c', 'o', 'm', 'p' ),
+ FT_IMAGE_TAG( FT_GLYPH_FORMAT_BITMAP, 'b', 'i', 't', 's' ),
+ FT_IMAGE_TAG( FT_GLYPH_FORMAT_OUTLINE, 'o', 'u', 't', 'l' ),
+ FT_IMAGE_TAG( FT_GLYPH_FORMAT_PLOTTER, 'p', 'l', 'o', 't' )
+
+ } FT_Glyph_Format;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* ft_glyph_format_xxx */
+ /* */
+ /* <Description> */
+ /* A list of deprecated constants. Use the corresponding */
+ /* @FT_Glyph_Format values instead. */
+ /* */
+ /* <Values> */
+ /* ft_glyph_format_none :: See @FT_GLYPH_FORMAT_NONE. */
+ /* ft_glyph_format_composite :: See @FT_GLYPH_FORMAT_COMPOSITE. */
+ /* ft_glyph_format_bitmap :: See @FT_GLYPH_FORMAT_BITMAP. */
+ /* ft_glyph_format_outline :: See @FT_GLYPH_FORMAT_OUTLINE. */
+ /* ft_glyph_format_plotter :: See @FT_GLYPH_FORMAT_PLOTTER. */
+ /* */
+#define ft_glyph_format_none FT_GLYPH_FORMAT_NONE
+#define ft_glyph_format_composite FT_GLYPH_FORMAT_COMPOSITE
+#define ft_glyph_format_bitmap FT_GLYPH_FORMAT_BITMAP
+#define ft_glyph_format_outline FT_GLYPH_FORMAT_OUTLINE
+#define ft_glyph_format_plotter FT_GLYPH_FORMAT_PLOTTER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** R A S T E R D E F I N I T I O N S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* A raster is a scan converter, in charge of rendering an outline into */
+ /* a a bitmap. This section contains the public API for rasters. */
+ /* */
+ /* Note that in FreeType 2, all rasters are now encapsulated within */
+ /* specific modules called `renderers'. See `freetype/ftrender.h' for */
+ /* more details on renderers. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* raster */
+ /* */
+ /* <Title> */
+ /* Scanline Converter */
+ /* */
+ /* <Abstract> */
+ /* How vectorial outlines are converted into bitmaps and pixmaps. */
+ /* */
+ /* <Description> */
+ /* This section contains technical definitions. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Raster */
+ /* */
+ /* <Description> */
+ /* A handle (pointer) to a raster object. Each object can be used */
+ /* independently to convert an outline into a bitmap or pixmap. */
+ /* */
+ typedef struct FT_RasterRec_* FT_Raster;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Span */
+ /* */
+ /* <Description> */
+ /* A structure used to model a single span of gray (or black) pixels */
+ /* when rendering a monochrome or anti-aliased bitmap. */
+ /* */
+ /* <Fields> */
+ /* x :: The span's horizontal start position. */
+ /* */
+ /* len :: The span's length in pixels. */
+ /* */
+ /* coverage :: The span color/coverage, ranging from 0 (background) */
+ /* to 255 (foreground). Only used for anti-aliased */
+ /* rendering. */
+ /* */
+ /* <Note> */
+ /* This structure is used by the span drawing callback type named */
+ /* @FT_SpanFunc which takes the y~coordinate of the span as a */
+ /* a parameter. */
+ /* */
+ /* The coverage value is always between 0 and 255. If you want less */
+ /* gray values, the callback function has to reduce them. */
+ /* */
+ typedef struct FT_Span_
+ {
+ short x;
+ unsigned short len;
+ unsigned char coverage;
+
+ } FT_Span;
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_SpanFunc */
+ /* */
+ /* <Description> */
+ /* A function used as a call-back by the anti-aliased renderer in */
+ /* order to let client applications draw themselves the gray pixel */
+ /* spans on each scan line. */
+ /* */
+ /* <Input> */
+ /* y :: The scanline's y~coordinate. */
+ /* */
+ /* count :: The number of spans to draw on this scanline. */
+ /* */
+ /* spans :: A table of `count' spans to draw on the scanline. */
+ /* */
+ /* user :: User-supplied data that is passed to the callback. */
+ /* */
+ /* <Note> */
+ /* This callback allows client applications to directly render the */
+ /* gray spans of the anti-aliased bitmap to any kind of surfaces. */
+ /* */
+ /* This can be used to write anti-aliased outlines directly to a */
+ /* given background bitmap, and even perform translucency. */
+ /* */
+ /* Note that the `count' field cannot be greater than a fixed value */
+ /* defined by the `FT_MAX_GRAY_SPANS' configuration macro in */
+ /* `ftoption.h'. By default, this value is set to~32, which means */
+ /* that if there are more than 32~spans on a given scanline, the */
+ /* callback is called several times with the same `y' parameter in */
+ /* order to draw all callbacks. */
+ /* */
+ /* Otherwise, the callback is only called once per scan-line, and */
+ /* only for those scanlines that do have `gray' pixels on them. */
+ /* */
+ typedef void
+ (*FT_SpanFunc)( int y,
+ int count,
+ const FT_Span* spans,
+ void* user );
+
+#define FT_Raster_Span_Func FT_SpanFunc
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_BitTest_Func */
+ /* */
+ /* <Description> */
+ /* THIS TYPE IS DEPRECATED. DO NOT USE IT. */
+ /* */
+ /* A function used as a call-back by the monochrome scan-converter */
+ /* to test whether a given target pixel is already set to the drawing */
+ /* `color'. These tests are crucial to implement drop-out control */
+ /* per-se the TrueType spec. */
+ /* */
+ /* <Input> */
+ /* y :: The pixel's y~coordinate. */
+ /* */
+ /* x :: The pixel's x~coordinate. */
+ /* */
+ /* user :: User-supplied data that is passed to the callback. */
+ /* */
+ /* <Return> */
+ /* 1~if the pixel is `set', 0~otherwise. */
+ /* */
+ typedef int
+ (*FT_Raster_BitTest_Func)( int y,
+ int x,
+ void* user );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_BitSet_Func */
+ /* */
+ /* <Description> */
+ /* THIS TYPE IS DEPRECATED. DO NOT USE IT. */
+ /* */
+ /* A function used as a call-back by the monochrome scan-converter */
+ /* to set an individual target pixel. This is crucial to implement */
+ /* drop-out control according to the TrueType specification. */
+ /* */
+ /* <Input> */
+ /* y :: The pixel's y~coordinate. */
+ /* */
+ /* x :: The pixel's x~coordinate. */
+ /* */
+ /* user :: User-supplied data that is passed to the callback. */
+ /* */
+ /* <Return> */
+ /* 1~if the pixel is `set', 0~otherwise. */
+ /* */
+ typedef void
+ (*FT_Raster_BitSet_Func)( int y,
+ int x,
+ void* user );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_RASTER_FLAG_XXX */
+ /* */
+ /* <Description> */
+ /* A list of bit flag constants as used in the `flags' field of a */
+ /* @FT_Raster_Params structure. */
+ /* */
+ /* <Values> */
+ /* FT_RASTER_FLAG_DEFAULT :: This value is 0. */
+ /* */
+ /* FT_RASTER_FLAG_AA :: This flag is set to indicate that an */
+ /* anti-aliased glyph image should be */
+ /* generated. Otherwise, it will be */
+ /* monochrome (1-bit). */
+ /* */
+ /* FT_RASTER_FLAG_DIRECT :: This flag is set to indicate direct */
+ /* rendering. In this mode, client */
+ /* applications must provide their own span */
+ /* callback. This lets them directly */
+ /* draw or compose over an existing bitmap. */
+ /* If this bit is not set, the target */
+ /* pixmap's buffer _must_ be zeroed before */
+ /* rendering. */
+ /* */
+ /* Note that for now, direct rendering is */
+ /* only possible with anti-aliased glyphs. */
+ /* */
+ /* FT_RASTER_FLAG_CLIP :: This flag is only used in direct */
+ /* rendering mode. If set, the output will */
+ /* be clipped to a box specified in the */
+ /* `clip_box' field of the */
+ /* @FT_Raster_Params structure. */
+ /* */
+ /* Note that by default, the glyph bitmap */
+ /* is clipped to the target pixmap, except */
+ /* in direct rendering mode where all spans */
+ /* are generated if no clipping box is set. */
+ /* */
+#define FT_RASTER_FLAG_DEFAULT 0x0
+#define FT_RASTER_FLAG_AA 0x1
+#define FT_RASTER_FLAG_DIRECT 0x2
+#define FT_RASTER_FLAG_CLIP 0x4
+
+ /* deprecated */
+#define ft_raster_flag_default FT_RASTER_FLAG_DEFAULT
+#define ft_raster_flag_aa FT_RASTER_FLAG_AA
+#define ft_raster_flag_direct FT_RASTER_FLAG_DIRECT
+#define ft_raster_flag_clip FT_RASTER_FLAG_CLIP
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Raster_Params */
+ /* */
+ /* <Description> */
+ /* A structure to hold the arguments used by a raster's render */
+ /* function. */
+ /* */
+ /* <Fields> */
+ /* target :: The target bitmap. */
+ /* */
+ /* source :: A pointer to the source glyph image (e.g., an */
+ /* @FT_Outline). */
+ /* */
+ /* flags :: The rendering flags. */
+ /* */
+ /* gray_spans :: The gray span drawing callback. */
+ /* */
+ /* black_spans :: The black span drawing callback. */
+ /* */
+ /* bit_test :: The bit test callback. UNIMPLEMENTED! */
+ /* */
+ /* bit_set :: The bit set callback. UNIMPLEMENTED! */
+ /* */
+ /* user :: User-supplied data that is passed to each drawing */
+ /* callback. */
+ /* */
+ /* clip_box :: An optional clipping box. It is only used in */
+ /* direct rendering mode. Note that coordinates here */
+ /* should be expressed in _integer_ pixels (and not in */
+ /* 26.6 fixed-point units). */
+ /* */
+ /* <Note> */
+ /* An anti-aliased glyph bitmap is drawn if the @FT_RASTER_FLAG_AA */
+ /* bit flag is set in the `flags' field, otherwise a monochrome */
+ /* bitmap is generated. */
+ /* */
+ /* If the @FT_RASTER_FLAG_DIRECT bit flag is set in `flags', the */
+ /* raster will call the `gray_spans' callback to draw gray pixel */
+ /* spans, in the case of an aa glyph bitmap, it will call */
+ /* `black_spans', and `bit_test' and `bit_set' in the case of a */
+ /* monochrome bitmap. This allows direct composition over a */
+ /* pre-existing bitmap through user-provided callbacks to perform the */
+ /* span drawing/composition. */
+ /* */
+ /* Note that the `bit_test' and `bit_set' callbacks are required when */
+ /* rendering a monochrome bitmap, as they are crucial to implement */
+ /* correct drop-out control as defined in the TrueType specification. */
+ /* */
+ typedef struct FT_Raster_Params_
+ {
+ const FT_Bitmap* target;
+ const void* source;
+ int flags;
+ FT_SpanFunc gray_spans;
+ FT_SpanFunc black_spans;
+ FT_Raster_BitTest_Func bit_test; /* doesn't work! */
+ FT_Raster_BitSet_Func bit_set; /* doesn't work! */
+ void* user;
+ FT_BBox clip_box;
+
+ } FT_Raster_Params;
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_NewFunc */
+ /* */
+ /* <Description> */
+ /* A function used to create a new raster object. */
+ /* */
+ /* <Input> */
+ /* memory :: A handle to the memory allocator. */
+ /* */
+ /* <Output> */
+ /* raster :: A handle to the new raster object. */
+ /* */
+ /* <Return> */
+ /* Error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* The `memory' parameter is a typeless pointer in order to avoid */
+ /* un-wanted dependencies on the rest of the FreeType code. In */
+ /* practice, it is an @FT_Memory object, i.e., a handle to the */
+ /* standard FreeType memory allocator. However, this field can be */
+ /* completely ignored by a given raster implementation. */
+ /* */
+ typedef int
+ (*FT_Raster_NewFunc)( void* memory,
+ FT_Raster* raster );
+
+#define FT_Raster_New_Func FT_Raster_NewFunc
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_DoneFunc */
+ /* */
+ /* <Description> */
+ /* A function used to destroy a given raster object. */
+ /* */
+ /* <Input> */
+ /* raster :: A handle to the raster object. */
+ /* */
+ typedef void
+ (*FT_Raster_DoneFunc)( FT_Raster raster );
+
+#define FT_Raster_Done_Func FT_Raster_DoneFunc
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_ResetFunc */
+ /* */
+ /* <Description> */
+ /* FreeType provides an area of memory called the `render pool', */
+ /* available to all registered rasters. This pool can be freely used */
+ /* during a given scan-conversion but is shared by all rasters. Its */
+ /* content is thus transient. */
+ /* */
+ /* This function is called each time the render pool changes, or just */
+ /* after a new raster object is created. */
+ /* */
+ /* <Input> */
+ /* raster :: A handle to the new raster object. */
+ /* */
+ /* pool_base :: The address in memory of the render pool. */
+ /* */
+ /* pool_size :: The size in bytes of the render pool. */
+ /* */
+ /* <Note> */
+ /* Rasters can ignore the render pool and rely on dynamic memory */
+ /* allocation if they want to (a handle to the memory allocator is */
+ /* passed to the raster constructor). However, this is not */
+ /* recommended for efficiency purposes. */
+ /* */
+ typedef void
+ (*FT_Raster_ResetFunc)( FT_Raster raster,
+ unsigned char* pool_base,
+ unsigned long pool_size );
+
+#define FT_Raster_Reset_Func FT_Raster_ResetFunc
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_SetModeFunc */
+ /* */
+ /* <Description> */
+ /* This function is a generic facility to change modes or attributes */
+ /* in a given raster. This can be used for debugging purposes, or */
+ /* simply to allow implementation-specific `features' in a given */
+ /* raster module. */
+ /* */
+ /* <Input> */
+ /* raster :: A handle to the new raster object. */
+ /* */
+ /* mode :: A 4-byte tag used to name the mode or property. */
+ /* */
+ /* args :: A pointer to the new mode/property to use. */
+ /* */
+ typedef int
+ (*FT_Raster_SetModeFunc)( FT_Raster raster,
+ unsigned long mode,
+ void* args );
+
+#define FT_Raster_Set_Mode_Func FT_Raster_SetModeFunc
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_RenderFunc */
+ /* */
+ /* <Description> */
+ /* Invoke a given raster to scan-convert a given glyph image into a */
+ /* target bitmap. */
+ /* */
+ /* <Input> */
+ /* raster :: A handle to the raster object. */
+ /* */
+ /* params :: A pointer to an @FT_Raster_Params structure used to */
+ /* store the rendering parameters. */
+ /* */
+ /* <Return> */
+ /* Error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* The exact format of the source image depends on the raster's glyph */
+ /* format defined in its @FT_Raster_Funcs structure. It can be an */
+ /* @FT_Outline or anything else in order to support a large array of */
+ /* glyph formats. */
+ /* */
+ /* Note also that the render function can fail and return a */
+ /* `FT_Err_Unimplemented_Feature' error code if the raster used does */
+ /* not support direct composition. */
+ /* */
+ /* XXX: For now, the standard raster doesn't support direct */
+ /* composition but this should change for the final release (see */
+ /* the files `demos/src/ftgrays.c' and `demos/src/ftgrays2.c' */
+ /* for examples of distinct implementations which support direct */
+ /* composition). */
+ /* */
+ typedef int
+ (*FT_Raster_RenderFunc)( FT_Raster raster,
+ const FT_Raster_Params* params );
+
+#define FT_Raster_Render_Func FT_Raster_RenderFunc
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Raster_Funcs */
+ /* */
+ /* <Description> */
+ /* A structure used to describe a given raster class to the library. */
+ /* */
+ /* <Fields> */
+ /* glyph_format :: The supported glyph format for this raster. */
+ /* */
+ /* raster_new :: The raster constructor. */
+ /* */
+ /* raster_reset :: Used to reset the render pool within the raster. */
+ /* */
+ /* raster_render :: A function to render a glyph into a given bitmap. */
+ /* */
+ /* raster_done :: The raster destructor. */
+ /* */
+ typedef struct FT_Raster_Funcs_
+ {
+ FT_Glyph_Format glyph_format;
+ FT_Raster_NewFunc raster_new;
+ FT_Raster_ResetFunc raster_reset;
+ FT_Raster_SetModeFunc raster_set_mode;
+ FT_Raster_RenderFunc raster_render;
+ FT_Raster_DoneFunc raster_done;
+
+ } FT_Raster_Funcs;
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTIMAGE_H__ */
+
+
+/* END */
+
+
+/* Local Variables: */
+/* coding: utf-8 */
+/* End: */
diff --git a/guilib/freetype2/include/freetype/ftmoderr.h b/guilib/freetype2/include/freetype/ftmoderr.h
new file mode 100644
index 0000000000..b0115dd0dd
--- /dev/null
+++ b/guilib/freetype2/include/freetype/ftmoderr.h
@@ -0,0 +1,155 @@
+/***************************************************************************/
+/* */
+/* ftmoderr.h */
+/* */
+/* FreeType module error offsets (specification). */
+/* */
+/* Copyright 2001, 2002, 2003, 2004, 2005 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the FreeType module error offsets. */
+ /* */
+ /* The lower byte gives the error code, the higher byte gives the */
+ /* module. The base module has error offset 0. For example, the error */
+ /* `FT_Err_Invalid_File_Format' has value 0x003, the error */
+ /* `TT_Err_Invalid_File_Format' has value 0x1103, the error */
+ /* `T1_Err_Invalid_File_Format' has value 0x1203, etc. */
+ /* */
+ /* Undefine the macro FT_CONFIG_OPTION_USE_MODULE_ERRORS in ftoption.h */
+ /* to make the higher byte always zero (disabling the module error */
+ /* mechanism). */
+ /* */
+ /* It can also be used to create a module error message table easily */
+ /* with something like */
+ /* */
+ /* { */
+ /* #undef __FTMODERR_H__ */
+ /* #define FT_MODERRDEF( e, v, s ) { FT_Mod_Err_ ## e, s }, */
+ /* #define FT_MODERR_START_LIST { */
+ /* #define FT_MODERR_END_LIST { 0, 0 } }; */
+ /* */
+ /* const struct */
+ /* { */
+ /* int mod_err_offset; */
+ /* const char* mod_err_msg */
+ /* } ft_mod_errors[] = */
+ /* */
+ /* #include FT_MODULE_ERRORS_H */
+ /* } */
+ /* */
+ /* To use such a table, all errors must be ANDed with 0xFF00 to remove */
+ /* the error code. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTMODERR_H__
+#define __FTMODERR_H__
+
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /***** *****/
+ /***** SETUP MACROS *****/
+ /***** *****/
+ /*******************************************************************/
+ /*******************************************************************/
+
+
+#undef FT_NEED_EXTERN_C
+
+#ifndef FT_MODERRDEF
+
+#ifdef FT_CONFIG_OPTION_USE_MODULE_ERRORS
+#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = v,
+#else
+#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = 0,
+#endif
+
+#define FT_MODERR_START_LIST enum {
+#define FT_MODERR_END_LIST FT_Mod_Err_Max };
+
+#ifdef __cplusplus
+#define FT_NEED_EXTERN_C
+ extern "C" {
+#endif
+
+#endif /* !FT_MODERRDEF */
+
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /***** *****/
+ /***** LIST MODULE ERROR BASES *****/
+ /***** *****/
+ /*******************************************************************/
+ /*******************************************************************/
+
+
+#ifdef FT_MODERR_START_LIST
+ FT_MODERR_START_LIST
+#endif
+
+
+ FT_MODERRDEF( Base, 0x000, "base module" )
+ FT_MODERRDEF( Autofit, 0x100, "autofitter module" )
+ FT_MODERRDEF( BDF, 0x200, "BDF module" )
+ FT_MODERRDEF( Cache, 0x300, "cache module" )
+ FT_MODERRDEF( CFF, 0x400, "CFF module" )
+ FT_MODERRDEF( CID, 0x500, "CID module" )
+ FT_MODERRDEF( Gzip, 0x600, "Gzip module" )
+ FT_MODERRDEF( LZW, 0x700, "LZW module" )
+ FT_MODERRDEF( OTvalid, 0x800, "OpenType validation module" )
+ FT_MODERRDEF( PCF, 0x900, "PCF module" )
+ FT_MODERRDEF( PFR, 0xA00, "PFR module" )
+ FT_MODERRDEF( PSaux, 0xB00, "PS auxiliary module" )
+ FT_MODERRDEF( PShinter, 0xC00, "PS hinter module" )
+ FT_MODERRDEF( PSnames, 0xD00, "PS names module" )
+ FT_MODERRDEF( Raster, 0xE00, "raster module" )
+ FT_MODERRDEF( SFNT, 0xF00, "SFNT module" )
+ FT_MODERRDEF( Smooth, 0x1000, "smooth raster module" )
+ FT_MODERRDEF( TrueType, 0x1100, "TrueType module" )
+ FT_MODERRDEF( Type1, 0x1200, "Type 1 module" )
+ FT_MODERRDEF( Type42, 0x1300, "Type 42 module" )
+ FT_MODERRDEF( Winfonts, 0x1400, "Windows FON/FNT module" )
+
+
+#ifdef FT_MODERR_END_LIST
+ FT_MODERR_END_LIST
+#endif
+
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /***** *****/
+ /***** CLEANUP *****/
+ /***** *****/
+ /*******************************************************************/
+ /*******************************************************************/
+
+
+#ifdef FT_NEED_EXTERN_C
+ }
+#endif
+
+#undef FT_MODERR_START_LIST
+#undef FT_MODERR_END_LIST
+#undef FT_MODERRDEF
+#undef FT_NEED_EXTERN_C
+
+
+#endif /* __FTMODERR_H__ */
+
+
+/* END */
diff --git a/guilib/freetype2/include/freetype/ftoutln.h b/guilib/freetype2/include/freetype/ftoutln.h
new file mode 100644
index 0000000000..d7d01e8270
--- /dev/null
+++ b/guilib/freetype2/include/freetype/ftoutln.h
@@ -0,0 +1,538 @@
+/***************************************************************************/
+/* */
+/* ftoutln.h */
+/* */
+/* Support for the FT_Outline type used to store glyph shapes of */
+/* most scalable font formats (specification). */
+/* */
+/* Copyright 1996-2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTOUTLN_H__
+#define __FTOUTLN_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#ifdef FREETYPE_H
+#error "freetype.h of FreeType 1 has been loaded!"
+#error "Please fix the directory search order for header files"
+#error "so that freetype.h of FreeType 2 is found first."
+#endif
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* outline_processing */
+ /* */
+ /* <Title> */
+ /* Outline Processing */
+ /* */
+ /* <Abstract> */
+ /* Functions to create, transform, and render vectorial glyph images. */
+ /* */
+ /* <Description> */
+ /* This section contains routines used to create and destroy scalable */
+ /* glyph images known as `outlines'. These can also be measured, */
+ /* transformed, and converted into bitmaps and pixmaps. */
+ /* */
+ /* <Order> */
+ /* FT_Outline */
+ /* FT_OUTLINE_FLAGS */
+ /* FT_Outline_New */
+ /* FT_Outline_Done */
+ /* FT_Outline_Copy */
+ /* FT_Outline_Translate */
+ /* FT_Outline_Transform */
+ /* FT_Outline_Embolden */
+ /* FT_Outline_Reverse */
+ /* FT_Outline_Check */
+ /* */
+ /* FT_Outline_Get_CBox */
+ /* FT_Outline_Get_BBox */
+ /* */
+ /* FT_Outline_Get_Bitmap */
+ /* FT_Outline_Render */
+ /* */
+ /* FT_Outline_Decompose */
+ /* FT_Outline_Funcs */
+ /* FT_Outline_MoveTo_Func */
+ /* FT_Outline_LineTo_Func */
+ /* FT_Outline_ConicTo_Func */
+ /* FT_Outline_CubicTo_Func */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Decompose */
+ /* */
+ /* <Description> */
+ /* Walk over an outline's structure to decompose it into individual */
+ /* segments and Bézier arcs. This function is also able to emit */
+ /* `move to' and `close to' operations to indicate the start and end */
+ /* of new contours in the outline. */
+ /* */
+ /* <Input> */
+ /* outline :: A pointer to the source target. */
+ /* */
+ /* func_interface :: A table of `emitters', i.e., function pointers */
+ /* called during decomposition to indicate path */
+ /* operations. */
+ /* */
+ /* <InOut> */
+ /* user :: A typeless pointer which is passed to each */
+ /* emitter during the decomposition. It can be */
+ /* used to store the state during the */
+ /* decomposition. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_Decompose( FT_Outline* outline,
+ const FT_Outline_Funcs* func_interface,
+ void* user );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_New */
+ /* */
+ /* <Description> */
+ /* Create a new outline of a given size. */
+ /* */
+ /* <Input> */
+ /* library :: A handle to the library object from where the */
+ /* outline is allocated. Note however that the new */
+ /* outline will *not* necessarily be *freed*, when */
+ /* destroying the library, by @FT_Done_FreeType. */
+ /* */
+ /* numPoints :: The maximal number of points within the outline. */
+ /* */
+ /* numContours :: The maximal number of contours within the outline. */
+ /* */
+ /* <Output> */
+ /* anoutline :: A handle to the new outline. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* The reason why this function takes a `library' parameter is simply */
+ /* to use the library's memory allocator. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_New( FT_Library library,
+ FT_UInt numPoints,
+ FT_Int numContours,
+ FT_Outline *anoutline );
+
+
+ FT_EXPORT( FT_Error )
+ FT_Outline_New_Internal( FT_Memory memory,
+ FT_UInt numPoints,
+ FT_Int numContours,
+ FT_Outline *anoutline );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Done */
+ /* */
+ /* <Description> */
+ /* Destroy an outline created with @FT_Outline_New. */
+ /* */
+ /* <Input> */
+ /* library :: A handle of the library object used to allocate the */
+ /* outline. */
+ /* */
+ /* outline :: A pointer to the outline object to be discarded. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* If the outline's `owner' field is not set, only the outline */
+ /* descriptor will be released. */
+ /* */
+ /* The reason why this function takes an `library' parameter is */
+ /* simply to use ft_mem_free(). */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_Done( FT_Library library,
+ FT_Outline* outline );
+
+
+ FT_EXPORT( FT_Error )
+ FT_Outline_Done_Internal( FT_Memory memory,
+ FT_Outline* outline );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Check */
+ /* */
+ /* <Description> */
+ /* Check the contents of an outline descriptor. */
+ /* */
+ /* <Input> */
+ /* outline :: A handle to a source outline. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_Check( FT_Outline* outline );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Get_CBox */
+ /* */
+ /* <Description> */
+ /* Return an outline's `control box'. The control box encloses all */
+ /* the outline's points, including Bézier control points. Though it */
+ /* coincides with the exact bounding box for most glyphs, it can be */
+ /* slightly larger in some situations (like when rotating an outline */
+ /* which contains Bézier outside arcs). */
+ /* */
+ /* Computing the control box is very fast, while getting the bounding */
+ /* box can take much more time as it needs to walk over all segments */
+ /* and arcs in the outline. To get the latter, you can use the */
+ /* `ftbbox' component which is dedicated to this single task. */
+ /* */
+ /* <Input> */
+ /* outline :: A pointer to the source outline descriptor. */
+ /* */
+ /* <Output> */
+ /* acbox :: The outline's control box. */
+ /* */
+ FT_EXPORT( void )
+ FT_Outline_Get_CBox( const FT_Outline* outline,
+ FT_BBox *acbox );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Translate */
+ /* */
+ /* <Description> */
+ /* Apply a simple translation to the points of an outline. */
+ /* */
+ /* <InOut> */
+ /* outline :: A pointer to the target outline descriptor. */
+ /* */
+ /* <Input> */
+ /* xOffset :: The horizontal offset. */
+ /* */
+ /* yOffset :: The vertical offset. */
+ /* */
+ FT_EXPORT( void )
+ FT_Outline_Translate( const FT_Outline* outline,
+ FT_Pos xOffset,
+ FT_Pos yOffset );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Copy */
+ /* */
+ /* <Description> */
+ /* Copy an outline into another one. Both objects must have the */
+ /* same sizes (number of points & number of contours) when this */
+ /* function is called. */
+ /* */
+ /* <Input> */
+ /* source :: A handle to the source outline. */
+ /* */
+ /* <Output> */
+ /* target :: A handle to the target outline. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_Copy( const FT_Outline* source,
+ FT_Outline *target );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Transform */
+ /* */
+ /* <Description> */
+ /* Apply a simple 2x2 matrix to all of an outline's points. Useful */
+ /* for applying rotations, slanting, flipping, etc. */
+ /* */
+ /* <InOut> */
+ /* outline :: A pointer to the target outline descriptor. */
+ /* */
+ /* <Input> */
+ /* matrix :: A pointer to the transformation matrix. */
+ /* */
+ /* <Note> */
+ /* You can use @FT_Outline_Translate if you need to translate the */
+ /* outline's points. */
+ /* */
+ FT_EXPORT( void )
+ FT_Outline_Transform( const FT_Outline* outline,
+ const FT_Matrix* matrix );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Embolden */
+ /* */
+ /* <Description> */
+ /* Embolden an outline. The new outline will be at most 4~times */
+ /* `strength' pixels wider and higher. You may think of the left and */
+ /* bottom borders as unchanged. */
+ /* */
+ /* Negative `strength' values to reduce the outline thickness are */
+ /* possible also. */
+ /* */
+ /* <InOut> */
+ /* outline :: A handle to the target outline. */
+ /* */
+ /* <Input> */
+ /* strength :: How strong the glyph is emboldened. Expressed in */
+ /* 26.6 pixel format. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* The used algorithm to increase or decrease the thickness of the */
+ /* glyph doesn't change the number of points; this means that certain */
+ /* situations like acute angles or intersections are sometimes */
+ /* handled incorrectly. */
+ /* */
+ /* If you need `better' metrics values you should call */
+ /* @FT_Outline_Get_CBox ot @FT_Outline_Get_BBox. */
+ /* */
+ /* Example call: */
+ /* */
+ /* { */
+ /* FT_Load_Glyph( face, index, FT_LOAD_DEFAULT ); */
+ /* if ( face->slot->format == FT_GLYPH_FORMAT_OUTLINE ) */
+ /* FT_Outline_Embolden( &face->slot->outline, strength ); */
+ /* } */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_Embolden( FT_Outline* outline,
+ FT_Pos strength );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Reverse */
+ /* */
+ /* <Description> */
+ /* Reverse the drawing direction of an outline. This is used to */
+ /* ensure consistent fill conventions for mirrored glyphs. */
+ /* */
+ /* <InOut> */
+ /* outline :: A pointer to the target outline descriptor. */
+ /* */
+ /* <Note> */
+ /* This function toggles the bit flag @FT_OUTLINE_REVERSE_FILL in */
+ /* the outline's `flags' field. */
+ /* */
+ /* It shouldn't be used by a normal client application, unless it */
+ /* knows what it is doing. */
+ /* */
+ FT_EXPORT( void )
+ FT_Outline_Reverse( FT_Outline* outline );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Get_Bitmap */
+ /* */
+ /* <Description> */
+ /* Render an outline within a bitmap. The outline's image is simply */
+ /* OR-ed to the target bitmap. */
+ /* */
+ /* <Input> */
+ /* library :: A handle to a FreeType library object. */
+ /* */
+ /* outline :: A pointer to the source outline descriptor. */
+ /* */
+ /* <InOut> */
+ /* abitmap :: A pointer to the target bitmap descriptor. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* This function does NOT CREATE the bitmap, it only renders an */
+ /* outline image within the one you pass to it! Consequently, the */
+ /* various fields in `abitmap' should be set accordingly. */
+ /* */
+ /* It will use the raster corresponding to the default glyph format. */
+ /* */
+ /* The value of the `num_grays' field in `abitmap' is ignored. If */
+ /* you select the gray-level rasterizer, and you want less than 256 */
+ /* gray levels, you have to use @FT_Outline_Render directly. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_Get_Bitmap( FT_Library library,
+ FT_Outline* outline,
+ const FT_Bitmap *abitmap );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Render */
+ /* */
+ /* <Description> */
+ /* Render an outline within a bitmap using the current scan-convert. */
+ /* This function uses an @FT_Raster_Params structure as an argument, */
+ /* allowing advanced features like direct composition, translucency, */
+ /* etc. */
+ /* */
+ /* <Input> */
+ /* library :: A handle to a FreeType library object. */
+ /* */
+ /* outline :: A pointer to the source outline descriptor. */
+ /* */
+ /* <InOut> */
+ /* params :: A pointer to an @FT_Raster_Params structure used to */
+ /* describe the rendering operation. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ /* <Note> */
+ /* You should know what you are doing and how @FT_Raster_Params works */
+ /* to use this function. */
+ /* */
+ /* The field `params.source' will be set to `outline' before the scan */
+ /* converter is called, which means that the value you give to it is */
+ /* actually ignored. */
+ /* */
+ /* The gray-level rasterizer always uses 256 gray levels. If you */
+ /* want less gray levels, you have to provide your own span callback. */
+ /* See the @FT_RASTER_FLAG_DIRECT value of the `flags' field in the */
+ /* @FT_Raster_Params structure for more details. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_Render( FT_Library library,
+ FT_Outline* outline,
+ FT_Raster_Params* params );
+
+
+ /**************************************************************************
+ *
+ * @enum:
+ * FT_Orientation
+ *
+ * @description:
+ * A list of values used to describe an outline's contour orientation.
+ *
+ * The TrueType and PostScript specifications use different conventions
+ * to determine whether outline contours should be filled or unfilled.
+ *
+ * @values:
+ * FT_ORIENTATION_TRUETYPE ::
+ * According to the TrueType specification, clockwise contours must
+ * be filled, and counter-clockwise ones must be unfilled.
+ *
+ * FT_ORIENTATION_POSTSCRIPT ::
+ * According to the PostScript specification, counter-clockwise contours
+ * must be filled, and clockwise ones must be unfilled.
+ *
+ * FT_ORIENTATION_FILL_RIGHT ::
+ * This is identical to @FT_ORIENTATION_TRUETYPE, but is used to
+ * remember that in TrueType, everything that is to the right of
+ * the drawing direction of a contour must be filled.
+ *
+ * FT_ORIENTATION_FILL_LEFT ::
+ * This is identical to @FT_ORIENTATION_POSTSCRIPT, but is used to
+ * remember that in PostScript, everything that is to the left of
+ * the drawing direction of a contour must be filled.
+ *
+ * FT_ORIENTATION_NONE ::
+ * The orientation cannot be determined. That is, different parts of
+ * the glyph have different orientation.
+ *
+ */
+ typedef enum FT_Orientation_
+ {
+ FT_ORIENTATION_TRUETYPE = 0,
+ FT_ORIENTATION_POSTSCRIPT = 1,
+ FT_ORIENTATION_FILL_RIGHT = FT_ORIENTATION_TRUETYPE,
+ FT_ORIENTATION_FILL_LEFT = FT_ORIENTATION_POSTSCRIPT,
+ FT_ORIENTATION_NONE
+
+ } FT_Orientation;
+
+
+ /**************************************************************************
+ *
+ * @function:
+ * FT_Outline_Get_Orientation
+ *
+ * @description:
+ * This function analyzes a glyph outline and tries to compute its
+ * fill orientation (see @FT_Orientation). This is done by computing
+ * the direction of each global horizontal and/or vertical extrema
+ * within the outline.
+ *
+ * Note that this will return @FT_ORIENTATION_TRUETYPE for empty
+ * outlines.
+ *
+ * @input:
+ * outline ::
+ * A handle to the source outline.
+ *
+ * @return:
+ * The orientation.
+ *
+ */
+ FT_EXPORT( FT_Orientation )
+ FT_Outline_Get_Orientation( FT_Outline* outline );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTOUTLN_H__ */
+
+
+/* END */
+
+
+/* Local Variables: */
+/* coding: utf-8 */
+/* End: */
diff --git a/guilib/freetype2/include/freetype/ftsystem.h b/guilib/freetype2/include/freetype/ftsystem.h
new file mode 100644
index 0000000000..a95b2c76b6
--- /dev/null
+++ b/guilib/freetype2/include/freetype/ftsystem.h
@@ -0,0 +1,346 @@
+/***************************************************************************/
+/* */
+/* ftsystem.h */
+/* */
+/* FreeType low-level system interface definition (specification). */
+/* */
+/* Copyright 1996-2001, 2002, 2005 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTSYSTEM_H__
+#define __FTSYSTEM_H__
+
+
+#include <ft2build.h>
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* system_interface */
+ /* */
+ /* <Title> */
+ /* System Interface */
+ /* */
+ /* <Abstract> */
+ /* How FreeType manages memory and i/o. */
+ /* */
+ /* <Description> */
+ /* This section contains various definitions related to memory */
+ /* management and i/o access. You need to understand this */
+ /* information if you want to use a custom memory manager or you own */
+ /* i/o streams. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* M E M O R Y M A N A G E M E N T */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************
+ *
+ * @type:
+ * FT_Memory
+ *
+ * @description:
+ * A handle to a given memory manager object, defined with an
+ * @FT_MemoryRec structure.
+ *
+ */
+ typedef struct FT_MemoryRec_* FT_Memory;
+
+
+ /*************************************************************************
+ *
+ * @functype:
+ * FT_Alloc_Func
+ *
+ * @description:
+ * A function used to allocate `size' bytes from `memory'.
+ *
+ * @input:
+ * memory ::
+ * A handle to the source memory manager.
+ *
+ * size ::
+ * The size in bytes to allocate.
+ *
+ * @return:
+ * Address of new memory block. 0~in case of failure.
+ *
+ */
+ typedef void*
+ (*FT_Alloc_Func)( FT_Memory memory,
+ long size );
+
+
+ /*************************************************************************
+ *
+ * @functype:
+ * FT_Free_Func
+ *
+ * @description:
+ * A function used to release a given block of memory.
+ *
+ * @input:
+ * memory ::
+ * A handle to the source memory manager.
+ *
+ * block ::
+ * The address of the target memory block.
+ *
+ */
+ typedef void
+ (*FT_Free_Func)( FT_Memory memory,
+ void* block );
+
+
+ /*************************************************************************
+ *
+ * @functype:
+ * FT_Realloc_Func
+ *
+ * @description:
+ * A function used to re-allocate a given block of memory.
+ *
+ * @input:
+ * memory ::
+ * A handle to the source memory manager.
+ *
+ * cur_size ::
+ * The block's current size in bytes.
+ *
+ * new_size ::
+ * The block's requested new size.
+ *
+ * block ::
+ * The block's current address.
+ *
+ * @return:
+ * New block address. 0~in case of memory shortage.
+ *
+ * @note:
+ * In case of error, the old block must still be available.
+ *
+ */
+ typedef void*
+ (*FT_Realloc_Func)( FT_Memory memory,
+ long cur_size,
+ long new_size,
+ void* block );
+
+
+ /*************************************************************************
+ *
+ * @struct:
+ * FT_MemoryRec
+ *
+ * @description:
+ * A structure used to describe a given memory manager to FreeType~2.
+ *
+ * @fields:
+ * user ::
+ * A generic typeless pointer for user data.
+ *
+ * alloc ::
+ * A pointer type to an allocation function.
+ *
+ * free ::
+ * A pointer type to an memory freeing function.
+ *
+ * realloc ::
+ * A pointer type to a reallocation function.
+ *
+ */
+ struct FT_MemoryRec_
+ {
+ void* user;
+ FT_Alloc_Func alloc;
+ FT_Free_Func free;
+ FT_Realloc_Func realloc;
+ };
+
+
+ /*************************************************************************/
+ /* */
+ /* I / O M A N A G E M E N T */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************
+ *
+ * @type:
+ * FT_Stream
+ *
+ * @description:
+ * A handle to an input stream.
+ *
+ */
+ typedef struct FT_StreamRec_* FT_Stream;
+
+
+ /*************************************************************************
+ *
+ * @struct:
+ * FT_StreamDesc
+ *
+ * @description:
+ * A union type used to store either a long or a pointer. This is used
+ * to store a file descriptor or a `FILE*' in an input stream.
+ *
+ */
+ typedef union FT_StreamDesc_
+ {
+ long value;
+ void* pointer;
+
+ } FT_StreamDesc;
+
+
+ /*************************************************************************
+ *
+ * @functype:
+ * FT_Stream_IoFunc
+ *
+ * @description:
+ * A function used to seek and read data from a given input stream.
+ *
+ * @input:
+ * stream ::
+ * A handle to the source stream.
+ *
+ * offset ::
+ * The offset of read in stream (always from start).
+ *
+ * buffer ::
+ * The address of the read buffer.
+ *
+ * count ::
+ * The number of bytes to read from the stream.
+ *
+ * @return:
+ * The number of bytes effectively read by the stream.
+ *
+ * @note:
+ * This function might be called to perform a seek or skip operation
+ * with a `count' of~0.
+ *
+ */
+ typedef unsigned long
+ (*FT_Stream_IoFunc)( FT_Stream stream,
+ unsigned long offset,
+ unsigned char* buffer,
+ unsigned long count );
+
+
+ /*************************************************************************
+ *
+ * @functype:
+ * FT_Stream_CloseFunc
+ *
+ * @description:
+ * A function used to close a given input stream.
+ *
+ * @input:
+ * stream ::
+ * A handle to the target stream.
+ *
+ */
+ typedef void
+ (*FT_Stream_CloseFunc)( FT_Stream stream );
+
+
+ /*************************************************************************
+ *
+ * @struct:
+ * FT_StreamRec
+ *
+ * @description:
+ * A structure used to describe an input stream.
+ *
+ * @input:
+ * base ::
+ * For memory-based streams, this is the address of the first stream
+ * byte in memory. This field should always be set to NULL for
+ * disk-based streams.
+ *
+ * size ::
+ * The stream size in bytes.
+ *
+ * pos ::
+ * The current position within the stream.
+ *
+ * descriptor ::
+ * This field is a union that can hold an integer or a pointer. It is
+ * used by stream implementations to store file descriptors or `FILE*'
+ * pointers.
+ *
+ * pathname ::
+ * This field is completely ignored by FreeType. However, it is often
+ * useful during debugging to use it to store the stream's filename
+ * (where available).
+ *
+ * read ::
+ * The stream's input function.
+ *
+ * close ::
+ * The stream;s close function.
+ *
+ * memory ::
+ * The memory manager to use to preload frames. This is set
+ * internally by FreeType and shouldn't be touched by stream
+ * implementations.
+ *
+ * cursor ::
+ * This field is set and used internally by FreeType when parsing
+ * frames.
+ *
+ * limit ::
+ * This field is set and used internally by FreeType when parsing
+ * frames.
+ *
+ */
+ typedef struct FT_StreamRec_
+ {
+ unsigned char* base;
+ unsigned long size;
+ unsigned long pos;
+
+ FT_StreamDesc descriptor;
+ FT_StreamDesc pathname;
+ FT_Stream_IoFunc read;
+ FT_Stream_CloseFunc close;
+
+ FT_Memory memory;
+ unsigned char* cursor;
+ unsigned char* limit;
+
+ } FT_StreamRec;
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTSYSTEM_H__ */
+
+
+/* END */
diff --git a/guilib/freetype2/include/freetype/fttypes.h b/guilib/freetype2/include/freetype/fttypes.h
new file mode 100644
index 0000000000..54f08e3e5a
--- /dev/null
+++ b/guilib/freetype2/include/freetype/fttypes.h
@@ -0,0 +1,587 @@
+/***************************************************************************/
+/* */
+/* fttypes.h */
+/* */
+/* FreeType simple types definitions (specification only). */
+/* */
+/* Copyright 1996-2001, 2002, 2004, 2006, 2007, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTTYPES_H__
+#define __FTTYPES_H__
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_SYSTEM_H
+#include FT_IMAGE_H
+
+#include <stddef.h>
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* basic_types */
+ /* */
+ /* <Title> */
+ /* Basic Data Types */
+ /* */
+ /* <Abstract> */
+ /* The basic data types defined by the library. */
+ /* */
+ /* <Description> */
+ /* This section contains the basic data types defined by FreeType~2, */
+ /* ranging from simple scalar types to bitmap descriptors. More */
+ /* font-specific structures are defined in a different section. */
+ /* */
+ /* <Order> */
+ /* FT_Byte */
+ /* FT_Bytes */
+ /* FT_Char */
+ /* FT_Int */
+ /* FT_UInt */
+ /* FT_Int16 */
+ /* FT_UInt16 */
+ /* FT_Int32 */
+ /* FT_UInt32 */
+ /* FT_Short */
+ /* FT_UShort */
+ /* FT_Long */
+ /* FT_ULong */
+ /* FT_Bool */
+ /* FT_Offset */
+ /* FT_PtrDist */
+ /* FT_String */
+ /* FT_Tag */
+ /* FT_Error */
+ /* FT_Fixed */
+ /* FT_Pointer */
+ /* FT_Pos */
+ /* FT_Vector */
+ /* FT_BBox */
+ /* FT_Matrix */
+ /* FT_FWord */
+ /* FT_UFWord */
+ /* FT_F2Dot14 */
+ /* FT_UnitVector */
+ /* FT_F26Dot6 */
+ /* */
+ /* */
+ /* FT_Generic */
+ /* FT_Generic_Finalizer */
+ /* */
+ /* FT_Bitmap */
+ /* FT_Pixel_Mode */
+ /* FT_Palette_Mode */
+ /* FT_Glyph_Format */
+ /* FT_IMAGE_TAG */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Bool */
+ /* */
+ /* <Description> */
+ /* A typedef of unsigned char, used for simple booleans. As usual, */
+ /* values 1 and~0 represent true and false, respectively. */
+ /* */
+ typedef unsigned char FT_Bool;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_FWord */
+ /* */
+ /* <Description> */
+ /* A signed 16-bit integer used to store a distance in original font */
+ /* units. */
+ /* */
+ typedef signed short FT_FWord; /* distance in FUnits */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_UFWord */
+ /* */
+ /* <Description> */
+ /* An unsigned 16-bit integer used to store a distance in original */
+ /* font units. */
+ /* */
+ typedef unsigned short FT_UFWord; /* unsigned distance */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Char */
+ /* */
+ /* <Description> */
+ /* A simple typedef for the _signed_ char type. */
+ /* */
+ typedef signed char FT_Char;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Byte */
+ /* */
+ /* <Description> */
+ /* A simple typedef for the _unsigned_ char type. */
+ /* */
+ typedef unsigned char FT_Byte;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Bytes */
+ /* */
+ /* <Description> */
+ /* A typedef for constant memory areas. */
+ /* */
+ typedef const FT_Byte* FT_Bytes;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Tag */
+ /* */
+ /* <Description> */
+ /* A typedef for 32-bit tags (as used in the SFNT format). */
+ /* */
+ typedef FT_UInt32 FT_Tag;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_String */
+ /* */
+ /* <Description> */
+ /* A simple typedef for the char type, usually used for strings. */
+ /* */
+ typedef char FT_String;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Short */
+ /* */
+ /* <Description> */
+ /* A typedef for signed short. */
+ /* */
+ typedef signed short FT_Short;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_UShort */
+ /* */
+ /* <Description> */
+ /* A typedef for unsigned short. */
+ /* */
+ typedef unsigned short FT_UShort;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Int */
+ /* */
+ /* <Description> */
+ /* A typedef for the int type. */
+ /* */
+ typedef signed int FT_Int;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_UInt */
+ /* */
+ /* <Description> */
+ /* A typedef for the unsigned int type. */
+ /* */
+ typedef unsigned int FT_UInt;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Long */
+ /* */
+ /* <Description> */
+ /* A typedef for signed long. */
+ /* */
+ typedef signed long FT_Long;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_ULong */
+ /* */
+ /* <Description> */
+ /* A typedef for unsigned long. */
+ /* */
+ typedef unsigned long FT_ULong;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_F2Dot14 */
+ /* */
+ /* <Description> */
+ /* A signed 2.14 fixed float type used for unit vectors. */
+ /* */
+ typedef signed short FT_F2Dot14;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_F26Dot6 */
+ /* */
+ /* <Description> */
+ /* A signed 26.6 fixed float type used for vectorial pixel */
+ /* coordinates. */
+ /* */
+ typedef signed long FT_F26Dot6;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Fixed */
+ /* */
+ /* <Description> */
+ /* This type is used to store 16.16 fixed float values, like scaling */
+ /* values or matrix coefficients. */
+ /* */
+ typedef signed long FT_Fixed;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Error */
+ /* */
+ /* <Description> */
+ /* The FreeType error code type. A value of~0 is always interpreted */
+ /* as a successful operation. */
+ /* */
+ typedef int FT_Error;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Pointer */
+ /* */
+ /* <Description> */
+ /* A simple typedef for a typeless pointer. */
+ /* */
+ typedef void* FT_Pointer;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Offset */
+ /* */
+ /* <Description> */
+ /* This is equivalent to the ANSI~C `size_t' type, i.e., the largest */
+ /* _unsigned_ integer type used to express a file size or position, */
+ /* or a memory block size. */
+ /* */
+ typedef size_t FT_Offset;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_PtrDist */
+ /* */
+ /* <Description> */
+ /* This is equivalent to the ANSI~C `ptrdiff_t' type, i.e., the */
+ /* largest _signed_ integer type used to express the distance */
+ /* between two pointers. */
+ /* */
+ typedef ft_ptrdiff_t FT_PtrDist;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_UnitVector */
+ /* */
+ /* <Description> */
+ /* A simple structure used to store a 2D vector unit vector. Uses */
+ /* FT_F2Dot14 types. */
+ /* */
+ /* <Fields> */
+ /* x :: Horizontal coordinate. */
+ /* */
+ /* y :: Vertical coordinate. */
+ /* */
+ typedef struct FT_UnitVector_
+ {
+ FT_F2Dot14 x;
+ FT_F2Dot14 y;
+
+ } FT_UnitVector;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Matrix */
+ /* */
+ /* <Description> */
+ /* A simple structure used to store a 2x2 matrix. Coefficients are */
+ /* in 16.16 fixed float format. The computation performed is: */
+ /* */
+ /* { */
+ /* x' = x*xx + y*xy */
+ /* y' = x*yx + y*yy */
+ /* } */
+ /* */
+ /* <Fields> */
+ /* xx :: Matrix coefficient. */
+ /* */
+ /* xy :: Matrix coefficient. */
+ /* */
+ /* yx :: Matrix coefficient. */
+ /* */
+ /* yy :: Matrix coefficient. */
+ /* */
+ typedef struct FT_Matrix_
+ {
+ FT_Fixed xx, xy;
+ FT_Fixed yx, yy;
+
+ } FT_Matrix;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Data */
+ /* */
+ /* <Description> */
+ /* Read-only binary data represented as a pointer and a length. */
+ /* */
+ /* <Fields> */
+ /* pointer :: The data. */
+ /* */
+ /* length :: The length of the data in bytes. */
+ /* */
+ typedef struct FT_Data_
+ {
+ const FT_Byte* pointer;
+ FT_Int length;
+
+ } FT_Data;
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Generic_Finalizer */
+ /* */
+ /* <Description> */
+ /* Describe a function used to destroy the `client' data of any */
+ /* FreeType object. See the description of the @FT_Generic type for */
+ /* details of usage. */
+ /* */
+ /* <Input> */
+ /* The address of the FreeType object which is under finalization. */
+ /* Its client data is accessed through its `generic' field. */
+ /* */
+ typedef void (*FT_Generic_Finalizer)(void* object);
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Generic */
+ /* */
+ /* <Description> */
+ /* Client applications often need to associate their own data to a */
+ /* variety of FreeType core objects. For example, a text layout API */
+ /* might want to associate a glyph cache to a given size object. */
+ /* */
+ /* Most FreeType object contains a `generic' field, of type */
+ /* FT_Generic, which usage is left to client applications and font */
+ /* servers. */
+ /* */
+ /* It can be used to store a pointer to client-specific data, as well */
+ /* as the address of a `finalizer' function, which will be called by */
+ /* FreeType when the object is destroyed (for example, the previous */
+ /* client example would put the address of the glyph cache destructor */
+ /* in the `finalizer' field). */
+ /* */
+ /* <Fields> */
+ /* data :: A typeless pointer to any client-specified data. This */
+ /* field is completely ignored by the FreeType library. */
+ /* */
+ /* finalizer :: A pointer to a `generic finalizer' function, which */
+ /* will be called when the object is destroyed. If this */
+ /* field is set to NULL, no code will be called. */
+ /* */
+ typedef struct FT_Generic_
+ {
+ void* data;
+ FT_Generic_Finalizer finalizer;
+
+ } FT_Generic;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Macro> */
+ /* FT_MAKE_TAG */
+ /* */
+ /* <Description> */
+ /* This macro converts four-letter tags which are used to label */
+ /* TrueType tables into an unsigned long to be used within FreeType. */
+ /* */
+ /* <Note> */
+ /* The produced values *must* be 32-bit integers. Don't redefine */
+ /* this macro. */
+ /* */
+#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
+ ( ( (FT_ULong)_x1 << 24 ) | \
+ ( (FT_ULong)_x2 << 16 ) | \
+ ( (FT_ULong)_x3 << 8 ) | \
+ (FT_ULong)_x4 )
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /* */
+ /* L I S T M A N A G E M E N T */
+ /* */
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* list_processing */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_ListNode */
+ /* */
+ /* <Description> */
+ /* Many elements and objects in FreeType are listed through an */
+ /* @FT_List record (see @FT_ListRec). As its name suggests, an */
+ /* FT_ListNode is a handle to a single list element. */
+ /* */
+ typedef struct FT_ListNodeRec_* FT_ListNode;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_List */
+ /* */
+ /* <Description> */
+ /* A handle to a list record (see @FT_ListRec). */
+ /* */
+ typedef struct FT_ListRec_* FT_List;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_ListNodeRec */
+ /* */
+ /* <Description> */
+ /* A structure used to hold a single list element. */
+ /* */
+ /* <Fields> */
+ /* prev :: The previous element in the list. NULL if first. */
+ /* */
+ /* next :: The next element in the list. NULL if last. */
+ /* */
+ /* data :: A typeless pointer to the listed object. */
+ /* */
+ typedef struct FT_ListNodeRec_
+ {
+ FT_ListNode prev;
+ FT_ListNode next;
+ void* data;
+
+ } FT_ListNodeRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_ListRec */
+ /* */
+ /* <Description> */
+ /* A structure used to hold a simple doubly-linked list. These are */
+ /* used in many parts of FreeType. */
+ /* */
+ /* <Fields> */
+ /* head :: The head (first element) of doubly-linked list. */
+ /* */
+ /* tail :: The tail (last element) of doubly-linked list. */
+ /* */
+ typedef struct FT_ListRec_
+ {
+ FT_ListNode head;
+ FT_ListNode tail;
+
+ } FT_ListRec;
+
+
+ /* */
+
+#define FT_IS_EMPTY( list ) ( (list).head == 0 )
+
+ /* return base error code (without module-specific prefix) */
+#define FT_ERROR_BASE( x ) ( (x) & 0xFF )
+
+ /* return module error code */
+#define FT_ERROR_MODULE( x ) ( (x) & 0xFF00U )
+
+#define FT_BOOL( x ) ( (FT_Bool)( x ) )
+
+FT_END_HEADER
+
+#endif /* __FTTYPES_H__ */
+
+
+/* END */
diff --git a/guilib/freetype2/include/ft2build.h b/guilib/freetype2/include/ft2build.h
new file mode 100644
index 0000000000..923d887df6
--- /dev/null
+++ b/guilib/freetype2/include/ft2build.h
@@ -0,0 +1,39 @@
+/***************************************************************************/
+/* */
+/* ft2build.h */
+/* */
+/* FreeType 2 build and setup macros. */
+/* (Generic version) */
+/* */
+/* Copyright 1996-2001, 2006 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file corresponds to the default `ft2build.h' file for */
+ /* FreeType 2. It uses the `freetype' include root. */
+ /* */
+ /* Note that specific platforms might use a different configuration. */
+ /* See builds/unix/ft2unix.h for an example. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FT2_BUILD_GENERIC_H__
+#define __FT2_BUILD_GENERIC_H__
+
+#include <freetype/config/ftheader.h>
+
+#endif /* __FT2_BUILD_GENERIC_H__ */
+
+
+/* END */
diff --git a/guilib/gui3d.h b/guilib/gui3d.h
new file mode 100644
index 0000000000..9ce1d988fb
--- /dev/null
+++ b/guilib/gui3d.h
@@ -0,0 +1,107 @@
+/*!
+\file gui3d.h
+\brief
+*/
+
+#ifndef GUILIB_GUI3D_H
+#define GUILIB_GUI3D_H
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+
+#define GAMMA_RAMP_FLAG D3DSGR_CALIBRATE
+
+#define D3DPRESENTFLAG_INTERLACED 1
+#define D3DPRESENTFLAG_WIDESCREEN 2
+#define D3DPRESENTFLAG_PROGRESSIVE 4
+
+#define D3DFMT_LIN_A8R8G8B8 D3DFMT_A8R8G8B8
+#define D3DFMT_LIN_X8R8G8B8 D3DFMT_X8R8G8B8
+#define D3DFMT_LIN_L8 D3DFMT_L8
+#define D3DFMT_LIN_D16 D3DFMT_D16
+#define D3DFMT_LIN_A8 D3DFMT_A8
+
+#define D3DPIXELSHADERDEF DWORD
+
+struct D3DTexture
+{
+ DWORD Common;
+ DWORD Data;
+ DWORD Lock;
+
+ DWORD Format; // Format information about the texture.
+ DWORD Size; // Size of a non power-of-2 texture, must be zero otherwise
+};
+
+#define D3DCOMMON_TYPE_MASK 0x0070000
+#define D3DCOMMON_TYPE_TEXTURE 0x0040000
+
+struct D3DPalette
+{
+ DWORD Common;
+ DWORD Data;
+ DWORD Lock;
+};
+
+typedef D3DPalette* LPDIRECT3DPALETTE8;
+
+#if defined(HAS_GL) || defined(HAS_GLES)
+
+namespace XBMC
+{
+ typedef void* DevicePtr;
+ typedef GLuint SurfacePtr;
+ typedef GLuint TexturePtr;
+ typedef void* PalettePtr; // elis change it
+ typedef GLint PixelFormat; // elis change it
+}
+
+#if defined(_LINUX) && !defined(GL_GLEXT_PROTOTYPES)
+#define GL_GLEXT_PROTOTYPES
+#endif
+
+#endif // HAS_GL
+
+#ifdef HAS_DX
+
+namespace XBMC
+{
+ typedef LPDIRECT3DDEVICE9 DevicePtr;
+ typedef LPDIRECT3DTEXTURE9 TexturePtr;
+ typedef LPDIRECT3DSURFACE9 SurfacePtr;
+ typedef LPDIRECT3DPALETTE8 PalettePtr;
+};
+
+#define DELETE_TEXTURE(texture) texture->Release()
+
+typedef uint32_t Uint32;
+
+#endif // HAS_DX
+
+#ifdef HAS_GLES
+
+#define GLchar char
+
+#endif
+#endif // GUILIB_GUI3D_H
diff --git a/guilib/guilib_win32.vcproj b/guilib/guilib_win32.vcproj
new file mode 100644
index 0000000000..794cf9d115
--- /dev/null
+++ b/guilib/guilib_win32.vcproj
@@ -0,0 +1,772 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="guilib"
+ ProjectGUID="{510441AC-B9E1-4B31-9C0C-EB3AD39D90C4}"
+ RootNamespace="guilib"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug (Win32)"
+ IntermediateDirectory="Debug (Win32)"
+ ConfigurationType="4"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/EHa"
+ Optimization="0"
+ AdditionalIncludeDirectories="../xbmc/;freetype2/include;../xbmc/lib/boost"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_MSVC;NOMINMAX;_WIN32_WINNT=0x0501;WINVER=0x0500"
+ StringPooling="FALSE"
+ MinimalRebuild="TRUE"
+ ExceptionHandling="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="include.h"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/guilib.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release (Win32)"
+ IntermediateDirectory="Release (Win32)"
+ ConfigurationType="4"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../xbmc/;freetype2/include;../xbmc/lib/boost"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_MSVC;NOMINMAX;_WIN32_WINNT=0x0501;WINVER=0x0500"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="include.h"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/guilib.lib"
+ IgnoreDefaultLibraryNames=""/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug (SDL)|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/EHa"
+ Optimization="0"
+ AdditionalIncludeDirectories="../guilib;../xbmc/Win32;../xbmc/;freetype2/include;../xbmc/lib/boost;../xbmc/utils;&quot;../xbmc/lib/libSDL-WIN32/include&quot;"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;HAS_SDL;_MSVC;NOMINMAX;_WIN32_WINNT=0x0501;WINVER=0x0500"
+ StringPooling="FALSE"
+ MinimalRebuild="TRUE"
+ ExceptionHandling="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ EnableEnhancedInstructionSet="0"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="include.h"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/guilib.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release (SDL)|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ GlobalOptimizations="TRUE"
+ FavorSizeOrSpeed="1"
+ AdditionalIncludeDirectories="../guilib;../xbmc/win32;../xbmc;freetype2\include;../xbmc/lib/boost;../xbmc/utils;&quot;../xbmc/lib/libSDL-WIN32/include&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;HAS_SDL;_MSVC;NOMINMAX;_WIN32_WINNT=0x0501;WINVER=0x0500"
+ MinimalRebuild="FALSE"
+ RuntimeLibrary="0"
+ EnableEnhancedInstructionSet="2"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="include.h"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/guilib.lib"
+ AdditionalLibraryDirectories=""
+ IgnoreAllDefaultLibraries="FALSE"
+ IgnoreDefaultLibraryNames=""/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath=".\AnimatedGif.cpp">
+ </File>
+ <File
+ RelativePath=".\AudioContext.cpp">
+ </File>
+ <File
+ RelativePath=".\DirectXGraphics.cpp">
+ </File>
+ <File
+ RelativePath=".\FrameBufferObject.cpp">
+ </File>
+ <File
+ RelativePath=".\GraphicContext.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIAudioManager.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIBaseContainer.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIBorderedImage.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIButtonControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIButtonScroller.cpp">
+ </File>
+ <File
+ RelativePath=".\GUICheckMarkControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIColorManager.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GuiControlFactory.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIControlGroup.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIControlGroupList.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIDialog.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIEditControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIFadeLabelControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIFixedListContainer.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIFont.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIFontManager.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIFontTTF.cpp">
+ </File>
+ <File
+ RelativePath=".\guiImage.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIIncludes.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIInfoColor.cpp">
+ </File>
+ <File
+ RelativePath=".\GUILabelControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIListContainer.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIListGroup.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIListItem.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIListItemLayout.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIListLabel.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIMessage.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIMoverControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIMultiImage.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIMultiSelectText.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIPanelContainer.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIProgressControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIRadioButtonControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIResizeControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIRSSControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIScrollBarControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUISelectButtonControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUISettingsSliderControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUISliderControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUISound.cpp">
+ </File>
+ <File
+ RelativePath=".\GUISpinControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUISpinControlEx.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIStandardWindow.cpp">
+ </File>
+ <File
+ RelativePath=".\GUITextBox.cpp">
+ </File>
+ <File
+ RelativePath=".\GUITextLayout.cpp">
+ </File>
+ <File
+ RelativePath=".\GUITexture.cpp">
+ </File>
+ <File
+ RelativePath=".\GUITextureD3D.cpp">
+ </File>
+ <File
+ RelativePath=".\GUITextureGL.cpp">
+ </File>
+ <File
+ RelativePath=".\GUITextureSDL.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIToggleButtonControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIVideoControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIVisualisationControl.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIWindow.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIWindowManager.cpp">
+ </File>
+ <File
+ RelativePath=".\GUIWrappingListContainer.cpp">
+ </File>
+ <File
+ RelativePath=".\include.cpp">
+ </File>
+ <File
+ RelativePath=".\IWindowManagerCallback.cpp">
+ </File>
+ <File
+ RelativePath=".\Key.cpp">
+ </File>
+ <File
+ RelativePath=".\LocalizeStrings.cpp">
+ </File>
+ <File
+ RelativePath=".\Shader.cpp">
+ </File>
+ <File
+ RelativePath=".\SkinInfo.cpp">
+ </File>
+ <File
+ RelativePath=".\Surface.cpp">
+ </File>
+ <File
+ RelativePath=".\TextureBundle.cpp">
+ </File>
+ <File
+ RelativePath=".\TextureManager.cpp">
+ </File>
+ <File
+ RelativePath=".\VisibleEffect.cpp">
+ </File>
+ <File
+ RelativePath=".\XMLUtils.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath=".\AnimatedGif.h">
+ </File>
+ <File
+ RelativePath=".\AudioContext.h">
+ </File>
+ <File
+ RelativePath=".\DirectXGraphics.h">
+ </File>
+ <File
+ RelativePath=".\FrameBufferObject.h">
+ </File>
+ <File
+ RelativePath=".\Geometry.h">
+ </File>
+ <File
+ RelativePath=".\GraphicContext.h">
+ </File>
+ <File
+ RelativePath=".\gui3d.h">
+ </File>
+ <File
+ RelativePath=".\GUIAudioManager.h">
+ </File>
+ <File
+ RelativePath=".\GUIBaseContainer.h">
+ </File>
+ <File
+ RelativePath=".\GUIBorderedImage.h">
+ </File>
+ <File
+ RelativePath=".\GUIButtonControl.h">
+ </File>
+ <File
+ RelativePath=".\GUIButtonScroller.h">
+ </File>
+ <File
+ RelativePath=".\GUICallback.h">
+ </File>
+ <File
+ RelativePath=".\GUICheckMarkControl.h">
+ </File>
+ <File
+ RelativePath=".\GUIColorManager.h">
+ </File>
+ <File
+ RelativePath=".\GUIControl.h">
+ </File>
+ <File
+ RelativePath=".\GuiControlFactory.h">
+ </File>
+ <File
+ RelativePath=".\GUIControlGroup.h">
+ </File>
+ <File
+ RelativePath=".\GUIControlGroupList.h">
+ </File>
+ <File
+ RelativePath=".\GUIDialog.h">
+ </File>
+ <File
+ RelativePath=".\GUIEditControl.h">
+ </File>
+ <File
+ RelativePath=".\GUIFadeLabelControl.h">
+ </File>
+ <File
+ RelativePath=".\GUIFixedListContainer.h">
+ </File>
+ <File
+ RelativePath=".\GUIFont.h">
+ </File>
+ <File
+ RelativePath=".\GUIFontManager.h">
+ </File>
+ <File
+ RelativePath=".\GUIFontTTF.h">
+ </File>
+ <File
+ RelativePath=".\guiImage.h">
+ </File>
+ <File
+ RelativePath=".\GUIIncludes.h">
+ </File>
+ <File
+ RelativePath=".\GUIInfoColor.h">
+ </File>
+ <File
+ RelativePath=".\GUILabelControl.h">
+ </File>
+ <File
+ RelativePath=".\GUIListContainer.h">
+ </File>
+ <File
+ RelativePath=".\GUIListGroup.h">
+ </File>
+ <File
+ RelativePath=".\GUIListItem.h">
+ </File>
+ <File
+ RelativePath=".\GUIListItemLayout.h">
+ </File>
+ <File
+ RelativePath=".\GUIListLabel.h">
+ </File>
+ <File
+ RelativePath=".\GUIMessage.h">
+ </File>
+ <File
+ RelativePath=".\GUIMoverControl.h">
+ </File>
+ <File
+ RelativePath=".\GUIMultiImage.h">
+ </File>
+ <File
+ RelativePath=".\GUIMultiSelectText.h">
+ </File>
+ <File
+ RelativePath=".\GUIPanelContainer.h">
+ </File>
+ <File
+ RelativePath=".\GUIProgressControl.h">
+ </File>
+ <File
+ RelativePath=".\GUIRadioButtonControl.h">
+ </File>
+ <File
+ RelativePath=".\GUIResizeControl.h">
+ </File>
+ <File
+ RelativePath=".\GUIRSSControl.h">
+ </File>
+ <File
+ RelativePath=".\GUIScrollBarControl.h">
+ </File>
+ <File
+ RelativePath=".\GUISelectButtonControl.h">
+ </File>
+ <File
+ RelativePath=".\GUISettingsSliderControl.h">
+ </File>
+ <File
+ RelativePath=".\GUISliderControl.h">
+ </File>
+ <File
+ RelativePath=".\GUISound.h">
+ </File>
+ <File
+ RelativePath=".\GUISpinControl.h">
+ </File>
+ <File
+ RelativePath=".\GUISpinControlEx.h">
+ </File>
+ <File
+ RelativePath=".\GUIStandardWindow.h">
+ </File>
+ <File
+ RelativePath=".\GUITextBox.h">
+ </File>
+ <File
+ RelativePath=".\GUITextLayout.h">
+ </File>
+ <File
+ RelativePath=".\GUITexture.h">
+ </File>
+ <File
+ RelativePath=".\GUITextureD3D.h">
+ </File>
+ <File
+ RelativePath=".\GUITextureGL.h">
+ </File>
+ <File
+ RelativePath=".\GUITextureSDL.h">
+ </File>
+ <File
+ RelativePath=".\GUIToggleButtonControl.h">
+ </File>
+ <File
+ RelativePath=".\GUIVideoControl.h">
+ </File>
+ <File
+ RelativePath=".\GUIVisualisationControl.h">
+ </File>
+ <File
+ RelativePath=".\GUIWindow.h">
+ </File>
+ <File
+ RelativePath=".\GUIWindowManager.h">
+ </File>
+ <File
+ RelativePath=".\GUIWrappingListContainer.h">
+ </File>
+ <File
+ RelativePath=".\IAudioDeviceChangedCallback.h">
+ </File>
+ <File
+ RelativePath=".\IMsgSenderCallback.h">
+ </File>
+ <File
+ RelativePath=".\IMsgTargetCallback.h">
+ </File>
+ <File
+ RelativePath=".\include.h">
+ </File>
+ <File
+ RelativePath=".\IWindowManagerCallback.h">
+ </File>
+ <File
+ RelativePath=".\Key.h">
+ </File>
+ <File
+ RelativePath=".\LocalizeStrings.h">
+ </File>
+ <File
+ RelativePath=".\Shader.h">
+ </File>
+ <File
+ RelativePath=".\SkinInfo.h">
+ </File>
+ <File
+ RelativePath=".\StdString.h">
+ </File>
+ <File
+ RelativePath=".\Surface.h">
+ </File>
+ <File
+ RelativePath=".\system.h">
+ </File>
+ <File
+ RelativePath=".\TextureBundle.h">
+ </File>
+ <File
+ RelativePath=".\TextureManager.h">
+ </File>
+ <File
+ RelativePath=".\TransformMatrix.h">
+ </File>
+ <File
+ RelativePath=".\Tween.h">
+ </File>
+ <File
+ RelativePath=".\VisibleEffect.h">
+ </File>
+ <File
+ RelativePath=".\XMLUtils.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+ </Filter>
+ <Filter
+ Name="tinyxml"
+ Filter="">
+ <File
+ RelativePath=".\tinyXML\tinystr.cpp">
+ </File>
+ <File
+ RelativePath=".\tinyXML\tinystr.h">
+ </File>
+ <File
+ RelativePath=".\tinyXML\tinyxml.cpp">
+ </File>
+ <File
+ RelativePath=".\tinyXML\tinyxml.h">
+ </File>
+ <File
+ RelativePath=".\tinyXML\tinyxmlerror.cpp">
+ </File>
+ <File
+ RelativePath=".\tinyXML\tinyxmlparser.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="common"
+ Filter="">
+ <File
+ RelativePath=".\common\DirectInput.cpp">
+ </File>
+ <File
+ RelativePath=".\common\DirectInput.h">
+ </File>
+ <File
+ RelativePath=".\common\DirectInputKeyboard.cpp">
+ </File>
+ <File
+ RelativePath=".\common\DirectInputKeyboard.h">
+ </File>
+ <File
+ RelativePath=".\common\DirectInputMouse.cpp">
+ </File>
+ <File
+ RelativePath=".\common\DirectInputMouse.h">
+ </File>
+ <File
+ RelativePath=".\common\Keyboard.cpp">
+ </File>
+ <File
+ RelativePath=".\common\Keyboard.h">
+ </File>
+ <File
+ RelativePath=".\common\Mouse.cpp">
+ </File>
+ <File
+ RelativePath=".\common\Mouse.h">
+ </File>
+ <File
+ RelativePath=".\common\SDLJoystick.cpp">
+ </File>
+ <File
+ RelativePath=".\common\SDLJoystick.h">
+ </File>
+ <File
+ RelativePath=".\common\SDLKeyboard.cpp">
+ </File>
+ <File
+ RelativePath=".\common\SDLKeyboard.h">
+ </File>
+ <File
+ RelativePath=".\common\SDLMouse.cpp">
+ </File>
+ <File
+ RelativePath=".\common\SDLMouse.h">
+ </File>
+ <Filter
+ Name="IRServerSuite"
+ Filter="">
+ <File
+ RelativePath=".\common\IRServerSuite\IRServerSuite.cpp">
+ </File>
+ <File
+ RelativePath=".\common\IRServerSuite\IRServerSuite.h">
+ </File>
+ <File
+ RelativePath=".\common\IRServerSuite\IrssMessage.cpp">
+ </File>
+ <File
+ RelativePath=".\common\IRServerSuite\IrssMessage.h">
+ </File>
+ </Filter>
+ </Filter>
+ <File
+ RelativePath=".\ReadMe.txt">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/guilib/system.h b/guilib/system.h
new file mode 100644
index 0000000000..c704b94125
--- /dev/null
+++ b/guilib/system.h
@@ -0,0 +1,191 @@
+#pragma once
+
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+/*****************
+ * All platforms
+ *****************/
+#ifndef HAS_SDL
+#define HAS_SDL
+#endif
+
+#define HAS_DVD_DRIVE
+#define HAS_DVD_SWSCALE
+#define HAS_DVDPLAYER
+#define HAS_EVENT_SERVER
+#define HAS_KARAOKE
+#define HAS_RAR
+#define HAS_SCREENSAVER
+#define HAS_PYTHON
+#define HAS_SHOUTCAST
+#define HAS_SYSINFO
+#define HAS_UPNP
+#define HAS_VIDEO_PLAYBACK
+#define HAS_VISUALISATION
+#define HAS_WEB_SERVER
+
+#define HAS_AC3_CODEC
+#define HAS_DTS_CODEC
+#define HAS_CDDA_RIPPER
+
+#define HAS_FILESYSTEM
+#define HAS_FILESYSTEM_SMB
+#define HAS_FILESYSTEM_CDDA
+#define HAS_FILESYSTEM_RTV
+#define HAS_FILESYSTEM_DAAP
+#define HAS_FILESYSTEM_SAP
+#define HAS_FILESYSTEM_VTP
+#define HAS_FILESYSTEM_HTSP
+#define HAS_FILESYSTEM_MMS
+#define HAS_CCXSTREAM
+
+/*****************
+ * Win32 Specific
+ *****************/
+
+#ifdef _WIN32
+#define HAS_SDL_JOYSTICK
+#define HAS_WIN32_NETWORK
+#define HAS_LIRC
+#define HAS_IRSERVERSUITE // depends on HAS_LIRC define
+#define HAS_AUDIO
+#endif
+
+/*****************
+ * Mac Specific
+ *****************/
+
+#ifdef __APPLE__
+#define HAS_ZEROCONF
+#define HAS_GL
+#define HAS_LINUX_NETWORK
+#define HAS_SDL_AUDIO
+#define HAS_SDL_OPENGL
+#define HAS_SDL_WIN_EVENTS
+#endif
+
+/*****************
+ * Linux Specific
+ *****************/
+
+#if defined(_LINUX) && !defined(__APPLE__)
+#ifndef HAS_SDL_OPENGL
+#define HAS_SDL_OPENGL
+#endif
+#ifdef HAS_AVAHI
+#define HAS_ZEROCONF
+#endif
+#define HAS_LCD
+#define HAS_HAL
+#define HAS_DBUS
+#define HAS_DBUS_SERVER
+#define HAS_GL
+#define HAS_GLX
+#define HAS_LINUX_NETWORK
+#define HAS_SDL_AUDIO
+#define HAS_LIRC
+#define HAS_SDL_WIN_EVENTS
+#endif
+
+/*****************
+ * SVN revision
+ *****************/
+
+#ifdef __APPLE__
+#include "../svn_revision.h"
+#endif
+
+#ifndef SVN_REV
+#define SVN_REV "Unknown"
+#endif
+
+#if defined(_LINUX) && !defined(__APPLE__)
+#include "../config.h"
+#endif
+
+/****************************************
+ * Additional platform specific includes
+ ****************************************/
+
+#ifdef _WIN32
+#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H))
+#include <winsock2.h>
+#endif
+#include <windows.h>
+#define DIRECTINPUT_VERSION 0x0800
+#include "mmsystem.h"
+#include "DInput.h"
+#include "DSound.h"
+#define DSSPEAKER_USE_DEFAULT DSSPEAKER_STEREO
+#define LPDIRECTSOUND8 LPDIRECTSOUND
+#undef GetFreeSpace
+#include "PlatformInclude.h"
+#include "D3D9.h" // On Win32, we're always using DirectX for something, whether it be the actual rendering
+#include "D3DX9.h" // or the reference video clock.
+#ifdef HAS_SDL
+#include "SDL\SDL.h"
+#endif
+#endif
+
+#ifdef _LINUX
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <errno.h>
+#include "PlatformInclude.h"
+#endif
+
+#ifdef HAS_GL
+#ifdef _WIN32
+#include "GL/glew.h"
+#include <GL/gl.h>
+#include <GL/glu.h>
+//#include <GL/wglext.h>
+#elif defined(__APPLE__)
+#include <GL/glew.h>
+#include <OpenGL/gl.h>
+#elif defined(_LINUX)
+#include <GL/glew.h>
+#include <GL/gl.h>
+#endif
+#endif
+
+#if HAS_GLES == 2
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#endif
+
+#define SAFE_DELETE(p) { delete (p); (p)=NULL; }
+#define SAFE_DELETE_ARRAY(p) { delete[] (p); (p)=NULL; }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+// Useful pixel colour manipulation macros
+#define GET_A(color) ((color >> 24) & 0xFF)
+#define GET_R(color) ((color >> 16) & 0xFF)
+#define GET_G(color) ((color >> 8) & 0xFF)
+#define GET_B(color) ((color >> 0) & 0xFF)
+
diff --git a/guilib/tinyXML/Makefile b/guilib/tinyXML/Makefile
new file mode 100644
index 0000000000..cdb40e5201
--- /dev/null
+++ b/guilib/tinyXML/Makefile
@@ -0,0 +1,6 @@
+INCLUDES=-I. -I../ -I../../xbmc -I../../xbmc/linux -I../../xbmc/utils
+SRCS=tinystr.cpp tinyxml.cpp tinyxmlerror.cpp tinyxmlparser.cpp
+LIB=tinyxml.a
+
+include ../../Makefile.include
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
diff --git a/guilib/tinyXML/tinystr.cpp b/guilib/tinyXML/tinystr.cpp
new file mode 100644
index 0000000000..681250714b
--- /dev/null
+++ b/guilib/tinyXML/tinystr.cpp
@@ -0,0 +1,116 @@
+/*
+www.sourceforge.net/projects/tinyxml
+Original file by Yves Berquin.
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+/*
+ * THIS FILE WAS ALTERED BY Tyge Løvset, 7. April 2005.
+ */
+
+
+#ifndef TIXML_USE_STL
+
+#include "tinystr.h"
+
+// Error value for find primitive
+const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1);
+
+
+// Null rep.
+TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } };
+
+
+void TiXmlString::reserve (size_type cap)
+{
+ if (cap > capacity())
+ {
+ TiXmlString tmp;
+ tmp.init(length(), cap);
+ memcpy(tmp.start(), data(), length());
+ swap(tmp);
+ }
+}
+
+
+TiXmlString& TiXmlString::assign(const char* str, size_type len)
+{
+ size_type cap = capacity();
+ if (len > cap || cap > 3*(len + 8))
+ {
+ TiXmlString tmp;
+ tmp.init(len);
+ memcpy(tmp.start(), str, len);
+ swap(tmp);
+ }
+ else
+ {
+ memmove(start(), str, len);
+ set_size(len);
+ }
+ return *this;
+}
+
+
+TiXmlString& TiXmlString::append(const char* str, size_type len)
+{
+ size_type newsize = length() + len;
+ if (newsize > capacity())
+ {
+ reserve (newsize + capacity());
+ }
+ memmove(finish(), str, len);
+ set_size(newsize);
+ return *this;
+}
+
+
+TiXmlString operator + (const TiXmlString & a, const TiXmlString & b)
+{
+ TiXmlString tmp;
+ tmp.reserve(a.length() + b.length());
+ tmp += a;
+ tmp += b;
+ return tmp;
+}
+
+TiXmlString operator + (const TiXmlString & a, const char* b)
+{
+ TiXmlString tmp;
+ TiXmlString::size_type b_len = static_cast<TiXmlString::size_type>( strlen(b) );
+ tmp.reserve(a.length() + b_len);
+ tmp += a;
+ tmp.append(b, b_len);
+ return tmp;
+}
+
+TiXmlString operator + (const char* a, const TiXmlString & b)
+{
+ TiXmlString tmp;
+ TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) );
+ tmp.reserve(a_len + b.length());
+ tmp.append(a, a_len);
+ tmp += b;
+ return tmp;
+}
+
+
+#endif // TIXML_USE_STL
diff --git a/guilib/tinyXML/tinystr.h b/guilib/tinyXML/tinystr.h
new file mode 100644
index 0000000000..3c2aa9d54d
--- /dev/null
+++ b/guilib/tinyXML/tinystr.h
@@ -0,0 +1,319 @@
+/*
+www.sourceforge.net/projects/tinyxml
+Original file by Yves Berquin.
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+/*
+ * THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005.
+ *
+ * - completely rewritten. compact, clean, and fast implementation.
+ * - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems)
+ * - fixed reserve() to work as per specification.
+ * - fixed buggy compares operator==(), operator<(), and operator>()
+ * - fixed operator+=() to take a const ref argument, following spec.
+ * - added "copy" constructor with length, and most compare operators.
+ * - added swap(), clear(), size(), capacity(), operator+().
+ */
+
+#ifndef TIXML_USE_STL
+
+#ifndef TIXML_STRING_INCLUDED
+#define TIXML_STRING_INCLUDED
+
+#include <assert.h>
+#include <string.h>
+
+/* The support for explicit isn't that universal, and it isn't really
+ required - it is used to check that the TiXmlString class isn't incorrectly
+ used. Be nice to old compilers and macro it here:
+*/
+#if defined(_MSC_VER) && (_MSC_VER >= 1200 )
+ // Microsoft visual studio, version 6 and higher.
+ #define TIXML_EXPLICIT explicit
+#elif defined(__GNUC__) && (__GNUC__ >= 3 )
+ // GCC version 3 and higher.s
+ #define TIXML_EXPLICIT explicit
+#else
+ #define TIXML_EXPLICIT
+#endif
+
+
+/*
+ TiXmlString is an emulation of a subset of the std::string template.
+ Its purpose is to allow compiling TinyXML on compilers with no or poor STL support.
+ Only the member functions relevant to the TinyXML project have been implemented.
+ The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase
+ a string and there's no more room, we allocate a buffer twice as big as we need.
+*/
+class TiXmlString
+{
+ public :
+ // The size type used
+ typedef size_t size_type;
+
+ // Error value for find primitive
+ static const size_type npos; // = -1;
+
+
+ // TiXmlString empty constructor
+ TiXmlString () : rep_(&nullrep_)
+ {
+ }
+
+ // TiXmlString copy constructor
+ TiXmlString ( const TiXmlString & copy) : rep_(0)
+ {
+ init(copy.length());
+ memcpy(start(), copy.data(), length());
+ }
+
+ // TiXmlString constructor, based on a string
+ TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0)
+ {
+ init( static_cast<size_type>( strlen(copy) ));
+ memcpy(start(), copy, length());
+ }
+
+ // TiXmlString constructor, based on a string
+ TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0)
+ {
+ init(len);
+ memcpy(start(), str, len);
+ }
+
+ // TiXmlString destructor
+ ~TiXmlString ()
+ {
+ quit();
+ }
+
+ // = operator
+ TiXmlString& operator = (const char * copy)
+ {
+ return assign( copy, (size_type)strlen(copy));
+ }
+
+ // = operator
+ TiXmlString& operator = (const TiXmlString & copy)
+ {
+ return assign(copy.start(), copy.length());
+ }
+
+
+ // += operator. Maps to append
+ TiXmlString& operator += (const char * suffix)
+ {
+ return append(suffix, static_cast<size_type>( strlen(suffix) ));
+ }
+
+ // += operator. Maps to append
+ TiXmlString& operator += (char single)
+ {
+ return append(&single, 1);
+ }
+
+ // += operator. Maps to append
+ TiXmlString& operator += (const TiXmlString & suffix)
+ {
+ return append(suffix.data(), suffix.length());
+ }
+
+
+ // Convert a TiXmlString into a null-terminated char *
+ const char * c_str () const { return rep_->str; }
+
+ // Convert a TiXmlString into a char * (need not be null terminated).
+ const char * data () const { return rep_->str; }
+
+ // Return the length of a TiXmlString
+ size_type length () const { return rep_->size; }
+
+ // Alias for length()
+ size_type size () const { return rep_->size; }
+
+ // Checks if a TiXmlString is empty
+ bool empty () const { return rep_->size == 0; }
+
+ // Return capacity of string
+ size_type capacity () const { return rep_->capacity; }
+
+
+ // single char extraction
+ const char& at (size_type index) const
+ {
+ assert( index < length() );
+ return rep_->str[ index ];
+ }
+
+ // [] operator
+ char& operator [] (size_type index) const
+ {
+ assert( index < length() );
+ return rep_->str[ index ];
+ }
+
+ // find a char in a string. Return TiXmlString::npos if not found
+ size_type find (char lookup) const
+ {
+ return find(lookup, 0);
+ }
+
+ // find a char in a string from an offset. Return TiXmlString::npos if not found
+ size_type find (char tofind, size_type offset) const
+ {
+ if (offset >= length()) return npos;
+
+ for (const char* p = c_str() + offset; *p != '\0'; ++p)
+ {
+ if (*p == tofind) return static_cast< size_type >( p - c_str() );
+ }
+ return npos;
+ }
+
+ void clear ()
+ {
+ //Lee:
+ //The original was just too strange, though correct:
+ // TiXmlString().swap(*this);
+ //Instead use the quit & re-init:
+ quit();
+ init(0,0);
+ }
+
+ /* Function to reserve a big amount of data when we know we'll need it. Be aware that this
+ function DOES NOT clear the content of the TiXmlString if any exists.
+ */
+ void reserve (size_type cap);
+
+ TiXmlString& assign (const char* str, size_type len);
+
+ TiXmlString& append (const char* str, size_type len);
+
+ void swap (TiXmlString& other)
+ {
+ Rep* r = rep_;
+ rep_ = other.rep_;
+ other.rep_ = r;
+ }
+
+ private:
+
+ void init(size_type sz) { init(sz, sz); }
+ void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; }
+ char* start() const { return rep_->str; }
+ char* finish() const { return rep_->str + rep_->size; }
+
+ struct Rep
+ {
+ size_type size, capacity;
+ char str[1];
+ };
+
+ void init(size_type sz, size_type cap)
+ {
+ if (cap)
+ {
+ // Lee: the original form:
+ // rep_ = static_cast<Rep*>(operator new(sizeof(Rep) + cap));
+ // doesn't work in some cases of new being overloaded. Switching
+ // to the normal allocation, although use an 'int' for systems
+ // that are overly picky about structure alignment.
+ const size_type bytesNeeded = sizeof(Rep) + cap;
+ const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int );
+ rep_ = reinterpret_cast<Rep*>( new int[ intsNeeded ] );
+
+ rep_->str[ rep_->size = sz ] = '\0';
+ rep_->capacity = cap;
+ }
+ else
+ {
+ rep_ = &nullrep_;
+ }
+ }
+
+ void quit()
+ {
+ if (rep_ != &nullrep_)
+ {
+ // The rep_ is really an array of ints. (see the allocator, above).
+ // Cast it back before delete, so the compiler won't incorrectly call destructors.
+ delete [] ( reinterpret_cast<int*>( rep_ ) );
+ }
+ }
+
+ Rep * rep_;
+ static Rep nullrep_;
+
+} ;
+
+
+inline bool operator == (const TiXmlString & a, const TiXmlString & b)
+{
+ return ( a.length() == b.length() ) // optimization on some platforms
+ && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare
+}
+inline bool operator < (const TiXmlString & a, const TiXmlString & b)
+{
+ return strcmp(a.c_str(), b.c_str()) < 0;
+}
+
+inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); }
+inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; }
+inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); }
+inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); }
+
+inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; }
+inline bool operator == (const char* a, const TiXmlString & b) { return b == a; }
+inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); }
+inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); }
+
+TiXmlString operator + (const TiXmlString & a, const TiXmlString & b);
+TiXmlString operator + (const TiXmlString & a, const char* b);
+TiXmlString operator + (const char* a, const TiXmlString & b);
+
+
+/*
+ TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString.
+ Only the operators that we need for TinyXML have been developped.
+*/
+class TiXmlOutStream : public TiXmlString
+{
+public :
+
+ // TiXmlOutStream << operator.
+ TiXmlOutStream & operator << (const TiXmlString & in)
+ {
+ *this += in;
+ return *this;
+ }
+
+ // TiXmlOutStream << operator.
+ TiXmlOutStream & operator << (const char * in)
+ {
+ *this += in;
+ return *this;
+ }
+
+} ;
+
+#endif // TIXML_STRING_INCLUDED
+#endif // TIXML_USE_STL
diff --git a/guilib/tinyXML/tinyxml.cpp b/guilib/tinyXML/tinyxml.cpp
new file mode 100644
index 0000000000..595a0914e9
--- /dev/null
+++ b/guilib/tinyXML/tinyxml.cpp
@@ -0,0 +1,2066 @@
+/*
+www.sourceforge.net/projects/tinyxml
+Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+#include <ctype.h>
+
+#ifdef TIXML_USE_STL
+#include <sstream>
+#include <iostream>
+#endif
+
+#include "tinyxml.h"
+
+#define USE_XBMC_FILESYSTEM
+
+#ifdef USE_XBMC_FILESYSTEM
+bool TiXmlBase::condenseWhiteSpace = false;
+#include "FileSystem/File.h"
+using namespace XFILE;
+#else
+bool TiXmlBase::condenseWhiteSpace = true;
+#endif
+
+
+
+void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString )
+{
+ int i=0;
+
+ while( i<(int)str.length() )
+ {
+ unsigned char c = (unsigned char) str[i];
+
+ if ( c == '&'
+ && i < ( (int)str.length() - 2 )
+ && str[i+1] == '#'
+ && str[i+2] == 'x' )
+ {
+ // Hexadecimal character reference.
+ // Pass through unchanged.
+ // &#xA9; -- copyright symbol, for example.
+ //
+ // The -1 is a bug fix from Rob Laveaux. It keeps
+ // an overflow from happening if there is no ';'.
+ // There are actually 2 ways to exit this loop -
+ // while fails (error case) and break (semicolon found).
+ // However, there is no mechanism (currently) for
+ // this function to return an error.
+ while ( i<(int)str.length()-1 )
+ {
+ outString->append( str.c_str() + i, 1 );
+ ++i;
+ if ( str[i] == ';' )
+ break;
+ }
+ }
+ else if ( c == '&' )
+ {
+ outString->append( entity[0].str, entity[0].strLength );
+ ++i;
+ }
+ else if ( c == '<' )
+ {
+ outString->append( entity[1].str, entity[1].strLength );
+ ++i;
+ }
+ else if ( c == '>' )
+ {
+ outString->append( entity[2].str, entity[2].strLength );
+ ++i;
+ }
+ else if ( c == '\"' )
+ {
+ outString->append( entity[3].str, entity[3].strLength );
+ ++i;
+ }
+ else if ( c == '\'' )
+ {
+ outString->append( entity[4].str, entity[4].strLength );
+ ++i;
+ }
+ else if ( c < 32 )
+ {
+ // Easy pass at non-alpha/numeric/symbol
+ // Below 32 is symbolic.
+ char buf[ 32 ];
+
+ #if defined(TIXML_SNPRINTF)
+ TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) );
+ #else
+ sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) );
+ #endif
+
+ //*ME: warning C4267: convert 'size_t' to 'int'
+ //*ME: Int-Cast to make compiler happy ...
+ outString->append( buf, (int)strlen( buf ) );
+ ++i;
+ }
+ else
+ {
+ //char realc = (char) c;
+ //outString->append( &realc, 1 );
+ *outString += (char) c; // somewhat more efficient function call.
+ ++i;
+ }
+ }
+}
+
+
+TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase()
+{
+ parent = 0;
+ type = _type;
+ firstChild = 0;
+ lastChild = 0;
+ prev = 0;
+ next = 0;
+}
+
+
+TiXmlNode::~TiXmlNode()
+{
+ TiXmlNode* node = firstChild;
+ TiXmlNode* temp = 0;
+
+ while ( node )
+ {
+ temp = node;
+ node = node->next;
+ delete temp;
+ }
+}
+
+
+void TiXmlNode::CopyTo( TiXmlNode* target ) const
+{
+ target->SetValue (value.c_str() );
+ target->userData = userData;
+}
+
+
+void TiXmlNode::Clear()
+{
+ TiXmlNode* node = firstChild;
+ TiXmlNode* temp = 0;
+
+ while ( node )
+ {
+ temp = node;
+ node = node->next;
+ delete temp;
+ }
+
+ firstChild = 0;
+ lastChild = 0;
+}
+
+
+TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )
+{
+ assert( node->parent == 0 || node->parent == this );
+ assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() );
+
+ if ( node->Type() == TiXmlNode::DOCUMENT )
+ {
+ delete node;
+ if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return 0;
+ }
+
+ node->parent = this;
+
+ node->prev = lastChild;
+ node->next = 0;
+
+ if ( lastChild )
+ lastChild->next = node;
+ else
+ firstChild = node; // it was an empty list.
+
+ lastChild = node;
+ return node;
+}
+
+
+TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis )
+{
+ if ( addThis.Type() == TiXmlNode::DOCUMENT )
+ {
+ if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return 0;
+ }
+ TiXmlNode* node = addThis.Clone();
+ if ( !node )
+ return 0;
+
+ return LinkEndChild( node );
+}
+
+
+TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis )
+{
+ if ( !beforeThis || beforeThis->parent != this ) {
+ return 0;
+ }
+ if ( addThis.Type() == TiXmlNode::DOCUMENT )
+ {
+ if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return 0;
+ }
+
+ TiXmlNode* node = addThis.Clone();
+ if ( !node )
+ return 0;
+ node->parent = this;
+
+ node->next = beforeThis;
+ node->prev = beforeThis->prev;
+ if ( beforeThis->prev )
+ {
+ beforeThis->prev->next = node;
+ }
+ else
+ {
+ assert( firstChild == beforeThis );
+ firstChild = node;
+ }
+ beforeThis->prev = node;
+ return node;
+}
+
+
+TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis )
+{
+ if ( !afterThis || afterThis->parent != this ) {
+ return 0;
+ }
+ if ( addThis.Type() == TiXmlNode::DOCUMENT )
+ {
+ if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return 0;
+ }
+
+ TiXmlNode* node = addThis.Clone();
+ if ( !node )
+ return 0;
+ node->parent = this;
+
+ node->prev = afterThis;
+ node->next = afterThis->next;
+ if ( afterThis->next )
+ {
+ afterThis->next->prev = node;
+ }
+ else
+ {
+ assert( lastChild == afterThis );
+ lastChild = node;
+ }
+ afterThis->next = node;
+ return node;
+}
+
+
+TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis )
+{
+ if ( replaceThis->parent != this )
+ return 0;
+
+ TiXmlNode* node = withThis.Clone();
+ if ( !node )
+ return 0;
+
+ node->next = replaceThis->next;
+ node->prev = replaceThis->prev;
+
+ if ( replaceThis->next )
+ replaceThis->next->prev = node;
+ else
+ lastChild = node;
+
+ if ( replaceThis->prev )
+ replaceThis->prev->next = node;
+ else
+ firstChild = node;
+
+ delete replaceThis;
+ node->parent = this;
+ return node;
+}
+
+
+bool TiXmlNode::RemoveChild( TiXmlNode* removeThis )
+{
+ if ( removeThis->parent != this )
+ {
+ assert( 0 );
+ return false;
+ }
+
+ if ( removeThis->next )
+ removeThis->next->prev = removeThis->prev;
+ else
+ lastChild = removeThis->prev;
+
+ if ( removeThis->prev )
+ removeThis->prev->next = removeThis->next;
+ else
+ firstChild = removeThis->next;
+
+ delete removeThis;
+ return true;
+}
+
+const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const
+{
+ const TiXmlNode* node;
+ for ( node = firstChild; node; node = node->next )
+ {
+ if ( strcmp( node->Value(), _value ) == 0 )
+ return node;
+ }
+ return 0;
+}
+
+
+const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const
+{
+ const TiXmlNode* node;
+ for ( node = lastChild; node; node = node->prev )
+ {
+ if ( strcmp( node->Value(), _value ) == 0 )
+ return node;
+ }
+ return 0;
+}
+
+
+const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const
+{
+ if ( !previous )
+ {
+ return FirstChild();
+ }
+ else
+ {
+ assert( previous->parent == this );
+ return previous->NextSibling();
+ }
+}
+
+
+const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const
+{
+ if ( !previous )
+ {
+ return FirstChild( val );
+ }
+ else
+ {
+ assert( previous->parent == this );
+ return previous->NextSibling( val );
+ }
+}
+
+
+const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const
+{
+ const TiXmlNode* node;
+ for ( node = next; node; node = node->next )
+ {
+ if ( strcmp( node->Value(), _value ) == 0 )
+ return node;
+ }
+ return 0;
+}
+
+
+const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const
+{
+ const TiXmlNode* node;
+ for ( node = prev; node; node = node->prev )
+ {
+ if ( strcmp( node->Value(), _value ) == 0 )
+ return node;
+ }
+ return 0;
+}
+
+
+void TiXmlElement::RemoveAttribute( const char * name )
+{
+ #ifdef TIXML_USE_STL
+ TIXML_STRING str( name );
+ TiXmlAttribute* node = attributeSet.Find( str );
+ #else
+ TiXmlAttribute* node = attributeSet.Find( name );
+ #endif
+ if ( node )
+ {
+ attributeSet.Remove( node );
+ delete node;
+ }
+}
+
+const TiXmlElement* TiXmlNode::FirstChildElement() const
+{
+ const TiXmlNode* node;
+
+ for ( node = FirstChild();
+ node;
+ node = node->NextSibling() )
+ {
+ if ( node->ToElement() )
+ return node->ToElement();
+ }
+ return 0;
+}
+
+
+const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const
+{
+ const TiXmlNode* node;
+
+ for ( node = FirstChild( _value );
+ node;
+ node = node->NextSibling( _value ) )
+ {
+ if ( node->ToElement() )
+ return node->ToElement();
+ }
+ return 0;
+}
+
+
+const TiXmlElement* TiXmlNode::NextSiblingElement() const
+{
+ const TiXmlNode* node;
+
+ for ( node = NextSibling();
+ node;
+ node = node->NextSibling() )
+ {
+ if ( node->ToElement() )
+ return node->ToElement();
+ }
+ return 0;
+}
+
+
+const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const
+{
+ const TiXmlNode* node;
+
+ for ( node = NextSibling( _value );
+ node;
+ node = node->NextSibling( _value ) )
+ {
+ if ( node->ToElement() )
+ return node->ToElement();
+ }
+ return 0;
+}
+
+
+const TiXmlDocument* TiXmlNode::GetDocument() const
+{
+ const TiXmlNode* node;
+
+ for( node = this; node; node = node->parent )
+ {
+ if ( node->ToDocument() )
+ return node->ToDocument();
+ }
+ return 0;
+}
+
+
+TiXmlElement::TiXmlElement (const char * _value)
+ : TiXmlNode( TiXmlNode::ELEMENT )
+{
+ firstChild = lastChild = 0;
+ value = _value;
+}
+
+
+#ifdef TIXML_USE_STL
+TiXmlElement::TiXmlElement( const std::string& _value )
+ : TiXmlNode( TiXmlNode::ELEMENT )
+{
+ firstChild = lastChild = 0;
+ value = _value;
+}
+#endif
+
+
+TiXmlElement::TiXmlElement( const TiXmlElement& copy)
+ : TiXmlNode( TiXmlNode::ELEMENT )
+{
+ firstChild = lastChild = 0;
+ copy.CopyTo( this );
+}
+
+
+void TiXmlElement::operator=( const TiXmlElement& base )
+{
+ ClearThis();
+ base.CopyTo( this );
+}
+
+
+TiXmlElement::~TiXmlElement()
+{
+ ClearThis();
+}
+
+
+void TiXmlElement::ClearThis()
+{
+ Clear();
+ while( attributeSet.First() )
+ {
+ TiXmlAttribute* node = attributeSet.First();
+ attributeSet.Remove( node );
+ delete node;
+ }
+}
+
+
+const char* TiXmlElement::Attribute( const char* name ) const
+{
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( node )
+ return node->Value();
+ return 0;
+}
+
+
+#ifdef TIXML_USE_STL
+const std::string* TiXmlElement::Attribute( const std::string& name ) const
+{
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( node )
+ return &node->ValueStr();
+ return 0;
+}
+#endif
+
+
+const char* TiXmlElement::Attribute( const char* name, int* i ) const
+{
+ const char* s = Attribute( name );
+ if ( i )
+ {
+ if ( s ) {
+ *i = atoi( s );
+ }
+ else {
+ *i = 0;
+ }
+ }
+ return s;
+}
+
+
+#ifdef TIXML_USE_STL
+const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const
+{
+ const std::string* s = Attribute( name );
+ if ( i )
+ {
+ if ( s ) {
+ *i = atoi( s->c_str() );
+ }
+ else {
+ *i = 0;
+ }
+ }
+ return s;
+}
+#endif
+
+
+const char* TiXmlElement::Attribute( const char* name, double* d ) const
+{
+ const char* s = Attribute( name );
+ if ( d )
+ {
+ if ( s ) {
+ *d = atof( s );
+ }
+ else {
+ *d = 0;
+ }
+ }
+ return s;
+}
+
+
+#ifdef TIXML_USE_STL
+const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const
+{
+ const std::string* s = Attribute( name );
+ if ( d )
+ {
+ if ( s ) {
+ *d = atof( s->c_str() );
+ }
+ else {
+ *d = 0;
+ }
+ }
+ return s;
+}
+#endif
+
+
+int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const
+{
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( !node )
+ return TIXML_NO_ATTRIBUTE;
+ return node->QueryIntValue( ival );
+}
+
+
+#ifdef TIXML_USE_STL
+int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const
+{
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( !node )
+ return TIXML_NO_ATTRIBUTE;
+ return node->QueryIntValue( ival );
+}
+#endif
+
+
+int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const
+{
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( !node )
+ return TIXML_NO_ATTRIBUTE;
+ return node->QueryDoubleValue( dval );
+}
+
+
+#ifdef TIXML_USE_STL
+int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const
+{
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( !node )
+ return TIXML_NO_ATTRIBUTE;
+ return node->QueryDoubleValue( dval );
+}
+#endif
+
+
+void TiXmlElement::SetAttribute( const char * name, int val )
+{
+ char buf[64];
+ #if defined(TIXML_SNPRINTF)
+ TIXML_SNPRINTF( buf, sizeof(buf), "%d", val );
+ #else
+ sprintf( buf, "%d", val );
+ #endif
+ SetAttribute( name, buf );
+}
+
+
+#ifdef TIXML_USE_STL
+void TiXmlElement::SetAttribute( const std::string& name, int val )
+{
+ std::ostringstream oss;
+ oss << val;
+ SetAttribute( name, oss.str() );
+}
+#endif
+
+
+void TiXmlElement::SetDoubleAttribute( const char * name, double val )
+{
+ char buf[256];
+ #if defined(TIXML_SNPRINTF)
+ TIXML_SNPRINTF( buf, sizeof(buf), "%f", val );
+ #else
+ sprintf( buf, "%f", val );
+ #endif
+ SetAttribute( name, buf );
+}
+
+
+void TiXmlElement::SetAttribute( const char * cname, const char * cvalue )
+{
+ #ifdef TIXML_USE_STL
+ TIXML_STRING _name( cname );
+ TIXML_STRING _value( cvalue );
+ #else
+ const char* _name = cname;
+ const char* _value = cvalue;
+ #endif
+
+ TiXmlAttribute* node = attributeSet.Find( _name );
+ if ( node )
+ {
+ node->SetValue( _value );
+ return;
+ }
+
+ TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue );
+ if ( attrib )
+ {
+ attributeSet.Add( attrib );
+ }
+ else
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ }
+}
+
+
+#ifdef TIXML_USE_STL
+void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value )
+{
+ TiXmlAttribute* node = attributeSet.Find( name );
+ if ( node )
+ {
+ node->SetValue( _value );
+ return;
+ }
+
+ TiXmlAttribute* attrib = new TiXmlAttribute( name, _value );
+ if ( attrib )
+ {
+ attributeSet.Add( attrib );
+ }
+ else
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ }
+}
+#endif
+
+
+void TiXmlElement::Print( FILE* cfile, int depth ) const
+{
+ int i;
+ assert( cfile );
+ for ( i=0; i<depth; i++ ) {
+ fprintf( cfile, " " );
+ }
+
+ fprintf( cfile, "<%s", value.c_str() );
+
+ const TiXmlAttribute* attrib;
+ for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
+ {
+ fprintf( cfile, " " );
+ attrib->Print( cfile, depth );
+ }
+
+ // There are 3 different formatting approaches:
+ // 1) An element without children is printed as a <foo /> node
+ // 2) An element with only a text child is printed as <foo> text </foo>
+ // 3) An element with children is printed on multiple lines.
+ TiXmlNode* node;
+ if ( !firstChild )
+ {
+ fprintf( cfile, " />" );
+ }
+ else if ( firstChild == lastChild && firstChild->ToText() )
+ {
+ fprintf( cfile, ">" );
+ firstChild->Print( cfile, depth + 1 );
+ fprintf( cfile, "</%s>", value.c_str() );
+ }
+ else
+ {
+ fprintf( cfile, ">" );
+
+ for ( node = firstChild; node; node=node->NextSibling() )
+ {
+ if ( !node->ToText() )
+ {
+ fprintf( cfile, "\n" );
+ }
+ node->Print( cfile, depth+1 );
+ }
+ fprintf( cfile, "\n" );
+ for( i=0; i<depth; ++i ) {
+ fprintf( cfile, " " );
+ }
+ fprintf( cfile, "</%s>", value.c_str() );
+ }
+}
+
+
+void TiXmlElement::CopyTo( TiXmlElement* target ) const
+{
+ // superclass:
+ TiXmlNode::CopyTo( target );
+
+ // Element class:
+ // Clone the attributes, then clone the children.
+ const TiXmlAttribute* attribute = 0;
+ for( attribute = attributeSet.First();
+ attribute;
+ attribute = attribute->Next() )
+ {
+ target->SetAttribute( attribute->Name(), attribute->Value() );
+ }
+
+ TiXmlNode* node = 0;
+ for ( node = firstChild; node; node = node->NextSibling() )
+ {
+ target->LinkEndChild( node->Clone() );
+ }
+}
+
+bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const
+{
+ if ( visitor->VisitEnter( *this, attributeSet.First() ) )
+ {
+ for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
+ {
+ if ( !node->Accept( visitor ) )
+ break;
+ }
+ }
+ return visitor->VisitExit( *this );
+}
+
+
+TiXmlNode* TiXmlElement::Clone() const
+{
+ TiXmlElement* clone = new TiXmlElement( Value() );
+ if ( !clone )
+ return 0;
+
+ CopyTo( clone );
+ return clone;
+}
+
+
+const char* TiXmlElement::GetText() const
+{
+ const TiXmlNode* child = this->FirstChild();
+ if ( child ) {
+ const TiXmlText* childText = child->ToText();
+ if ( childText ) {
+ return childText->Value();
+ }
+ }
+ return 0;
+}
+
+
+TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT )
+{
+ tabsize = 4;
+ useMicrosoftBOM = false;
+#ifdef HAS_ICONV
+ convertToUtf8 = false;
+ iconvContext = (iconv_t) -1;
+#endif
+ ClearError();
+}
+
+TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
+{
+ tabsize = 4;
+ useMicrosoftBOM = false;
+#ifdef HAS_ICONV
+ convertToUtf8 = false;
+ iconvContext = (iconv_t) -1;
+#endif
+ value = documentName;
+ ClearError();
+}
+
+
+#ifdef TIXML_USE_STL
+TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
+{
+ tabsize = 4;
+ useMicrosoftBOM = false;
+#ifdef HAS_ICONV
+ convertToUtf8 = false;
+ iconvContext = (iconv_t) -1;
+#endif
+ value = documentName;
+ ClearError();
+}
+#endif
+
+
+TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT )
+{
+ copy.CopyTo( this );
+}
+
+TiXmlDocument::~TiXmlDocument()
+{
+#ifdef HAS_ICONV
+ if (iconvContext != (iconv_t) -1)
+ {
+ iconv_close(iconvContext);
+ iconvContext = (iconv_t) -1;
+ }
+#endif
+}
+
+void TiXmlDocument::operator=( const TiXmlDocument& copy )
+{
+ Clear();
+ copy.CopyTo( this );
+}
+
+
+bool TiXmlDocument::LoadFile( TiXmlEncoding encoding )
+{
+ // See STL_STRING_BUG below.
+ //StringToBuffer buf( value );
+
+ return LoadFile( Value(), encoding );
+}
+
+
+bool TiXmlDocument::SaveFile() const
+{
+ // See STL_STRING_BUG below.
+// StringToBuffer buf( value );
+//
+// if ( buf.buffer && SaveFile( buf.buffer ) )
+// return true;
+//
+// return false;
+ return SaveFile( Value() );
+}
+
+#ifdef USE_XBMC_FILESYSTEM
+bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding )
+{
+ // There was a really terrifying little bug here. The code:
+ // value = filename
+ // in the STL case, cause the assignment method of the std::string to
+ // be called. What is strange, is that the std::string had the same
+ // address as it's c_str() method, and so bad things happen. Looks
+ // like a bug in the Microsoft STL implementation.
+ // Add an extra string to avoid the crash.
+ TIXML_STRING filename( _filename );
+ value = filename;
+
+ CFile file;
+ if (!file.Open(value))
+ {
+ SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return false;
+ }
+
+ // Delete the existing data:
+ Clear();
+ location.Clear();
+
+ // Get the file size, so we can pre-allocate the string. HUGE speed impact.
+ long length = -1;
+ __int64 filelen = file.GetLength();
+ if (filelen > 0)
+ length = (long)filelen;
+
+ // We might be streaming it, correct length will be fixed by reading
+ if( length < 0 )
+ length = 1024;
+
+ // Subtle bug here. TinyXml did use fgets. But from the XML spec:
+ // 2.11 End-of-Line Handling
+ // <snip>
+ // <quote>
+ // ...the XML processor MUST behave as if it normalized all line breaks in external
+ // parsed entities (including the document entity) on input, before parsing, by translating
+ // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to
+ // a single #xA character.
+ // </quote>
+ //
+ // It is not clear fgets does that, and certainly isn't clear it works cross platform.
+ // Generally, you expect fgets to translate from the convention of the OS to the c/unix
+ // convention, and not work generally.
+
+ /*
+ while( fgets( buf, sizeof(buf), file ) )
+ {
+ data += buf;
+ }
+ */
+
+ char* buf = (char*)malloc(length+1);
+ long pos = 0;
+ long len;
+ while( (len = file.Read(buf+pos, length-pos)) > 0 ) {
+ pos += len;
+ assert(pos <= length);
+ if(pos == length) {
+ length *= 2;
+ buf = (char*)realloc(buf, length);
+ }
+ }
+ length = pos;
+
+ file.Close();
+
+ // Strange case, but good to handle up front.
+ if ( length == 0 )
+ {
+ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return false;
+ }
+
+ // If we have a file, assume it is all one big XML file, and read it in.
+ // The document parser may decide the document ends sooner than the entire file, however.
+ TIXML_STRING data;
+ data.reserve( length );
+
+ const char* lastPos = buf;
+ const char* p = buf;
+
+ buf[length] = 0;
+ while( *p ) {
+ assert( p < (buf+length) );
+ if ( *p == 0xa ) {
+ // Newline character. No special rules for this. Append all the characters
+ // since the last string, and include the newline.
+ data.append( lastPos, (p-lastPos+1) ); // append, include the newline
+ ++p; // move past the newline
+ lastPos = p; // and point to the new buffer (may be 0)
+ assert( p <= (buf+length) );
+ }
+ else if ( *p == 0xd ) {
+ // Carriage return. Append what we have so far, then
+ // handle moving forward in the buffer.
+ if ( (p-lastPos) > 0 ) {
+ data.append( lastPos, p-lastPos ); // do not add the CR
+ }
+ data += (char)0xa; // a proper newline
+
+ if ( *(p+1) == 0xa ) {
+ // Carriage return - new line sequence
+ p += 2;
+ lastPos = p;
+ assert( p <= (buf+length) );
+ }
+ else {
+ // it was followed by something else...that is presumably characters again.
+ ++p;
+ lastPos = p;
+ assert( p <= (buf+length) );
+ }
+ }
+ else {
+ ++p;
+ }
+ }
+ // Handle any left over characters.
+ if ( p-lastPos ) {
+ data.append( lastPos, p-lastPos );
+ }
+ free(buf);
+ buf = 0;
+
+ Parse( data.c_str(), 0, encoding );
+
+ if ( Error() )
+ return false;
+ else
+ return true;
+}
+
+bool TiXmlDocument::SaveFile( const char *filename ) const
+{
+ XFILE::CFile file;
+ if (file.OpenForWrite(filename, true))
+ {
+ TiXmlPrinter printer;
+ Accept(&printer);
+ file.Write(printer.CStr(), printer.Size());
+ return true;
+ }
+ return false;
+}
+#else
+
+bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding )
+{
+ // There was a really terrifying little bug here. The code:
+ // value = filename
+ // in the STL case, cause the assignment method of the std::string to
+ // be called. What is strange, is that the std::string had the same
+ // address as it's c_str() method, and so bad things happen. Looks
+ // like a bug in the Microsoft STL implementation.
+ // Add an extra string to avoid the crash.
+ TIXML_STRING filename( _filename );
+ value = filename;
+
+ // reading in binary mode so that tinyxml can normalize the EOL
+ FILE* file = fopen( value.c_str(), "rb" );
+ if ( file )
+ {
+ bool result = LoadFile( file, encoding );
+ fclose( file );
+ return result;
+ }
+ else
+ {
+ SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return false;
+ }
+}
+
+bool TiXmlDocument::SaveFile( const char * filename ) const
+{
+ // The old c stuff lives on...
+ FILE* fp = fopen( filename, "w" );
+ if ( fp )
+ {
+ bool result = SaveFile( fp );
+ fclose( fp );
+ return result;
+ }
+ return false;
+}
+#endif
+
+bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding )
+{
+ if ( !file )
+ {
+ SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return false;
+ }
+
+ // Delete the existing data:
+ Clear();
+ location.Clear();
+
+ // Get the file size, so we can pre-allocate the string. HUGE speed impact.
+ long length = -1;
+ if( fseek( file, 0, SEEK_END ) == 0 ) {
+ length = ftell( file );
+ fseek( file, 0, SEEK_SET );
+ }
+
+ // We might be streaming it, correct length will be fixed by reading
+ if( length < 0 )
+ length = 1024;
+
+ // Subtle bug here. TinyXml did use fgets. But from the XML spec:
+ // 2.11 End-of-Line Handling
+ // <snip>
+ // <quote>
+ // ...the XML processor MUST behave as if it normalized all line breaks in external
+ // parsed entities (including the document entity) on input, before parsing, by translating
+ // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to
+ // a single #xA character.
+ // </quote>
+ //
+ // It is not clear fgets does that, and certainly isn't clear it works cross platform.
+ // Generally, you expect fgets to translate from the convention of the OS to the c/unix
+ // convention, and not work generally.
+
+ /*
+ while( fgets( buf, sizeof(buf), file ) )
+ {
+ data += buf;
+ }
+ */
+
+ char* buf = (char*)malloc(length+1);
+ long pos = 0;
+ long len;
+ while( (len = fread(buf+pos, 1, length-pos, file)) > 0 ) {
+ pos += len;
+ assert(pos <= length);
+ if(pos == length) {
+ length *= 2;
+ buf = (char*)realloc(buf, length);
+ }
+ }
+ length = pos;
+
+ // Strange case, but good to handle up front.
+ if ( length == 0 )
+ {
+ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return false;
+ }
+
+ // If we have a file, assume it is all one big XML file, and read it in.
+ // The document parser may decide the document ends sooner than the entire file, however.
+ TIXML_STRING data;
+ data.reserve( length );
+
+ const char* lastPos = buf;
+ const char* p = buf;
+
+ buf[length] = 0;
+ while( *p ) {
+ assert( p < (buf+length) );
+ if ( *p == 0xa ) {
+ // Newline character. No special rules for this. Append all the characters
+ // since the last string, and include the newline.
+ data.append( lastPos, (p-lastPos+1) ); // append, include the newline
+ ++p; // move past the newline
+ lastPos = p; // and point to the new buffer (may be 0)
+ assert( p <= (buf+length) );
+ }
+ else if ( *p == 0xd ) {
+ // Carriage return. Append what we have so far, then
+ // handle moving forward in the buffer.
+ if ( (p-lastPos) > 0 ) {
+ data.append( lastPos, p-lastPos ); // do not add the CR
+ }
+ data += (char)0xa; // a proper newline
+
+ if ( *(p+1) == 0xa ) {
+ // Carriage return - new line sequence
+ p += 2;
+ lastPos = p;
+ assert( p <= (buf+length) );
+ }
+ else {
+ // it was followed by something else...that is presumably characters again.
+ ++p;
+ lastPos = p;
+ assert( p <= (buf+length) );
+ }
+ }
+ else {
+ ++p;
+ }
+ }
+ // Handle any left over characters.
+ if ( p-lastPos ) {
+ data.append( lastPos, p-lastPos );
+ }
+ free(buf);
+ buf = 0;
+
+ Parse( data.c_str(), 0, encoding );
+
+ if ( Error() )
+ return false;
+ else
+ return true;
+}
+
+bool TiXmlDocument::SaveFile( FILE* fp ) const
+{
+ if ( useMicrosoftBOM )
+ {
+ const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
+ const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
+ const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
+
+ fputc( TIXML_UTF_LEAD_0, fp );
+ fputc( TIXML_UTF_LEAD_1, fp );
+ fputc( TIXML_UTF_LEAD_2, fp );
+ }
+ Print( fp, 0 );
+ return (ferror(fp) == 0);
+}
+
+
+void TiXmlDocument::CopyTo( TiXmlDocument* target ) const
+{
+ TiXmlNode::CopyTo( target );
+
+ target->error = error;
+ target->errorId = errorId;
+ target->errorDesc = errorDesc;
+ target->tabsize = tabsize;
+ target->errorLocation = errorLocation;
+ target->useMicrosoftBOM = useMicrosoftBOM;
+#ifdef HAS_ICONV
+ target->convertToUtf8 = convertToUtf8;
+ target->iconvContext = (iconv_t) -1;
+#endif
+
+ TiXmlNode* node = 0;
+ for ( node = firstChild; node; node = node->NextSibling() )
+ {
+ target->LinkEndChild( node->Clone() );
+ }
+}
+
+
+TiXmlNode* TiXmlDocument::Clone() const
+{
+ TiXmlDocument* clone = new TiXmlDocument();
+ if ( !clone )
+ return 0;
+
+ CopyTo( clone );
+ return clone;
+}
+
+
+void TiXmlDocument::Print( FILE* cfile, int depth ) const
+{
+ assert( cfile );
+ for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
+ {
+ node->Print( cfile, depth );
+ fprintf( cfile, "\n" );
+ }
+}
+
+
+bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const
+{
+ if ( visitor->VisitEnter( *this ) )
+ {
+ for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
+ {
+ if ( !node->Accept( visitor ) )
+ break;
+ }
+ }
+ return visitor->VisitExit( *this );
+}
+
+
+const TiXmlAttribute* TiXmlAttribute::Next() const
+{
+ // We are using knowledge of the sentinel. The sentinel
+ // have a value or name.
+ if ( next->value.empty() && next->name.empty() )
+ return 0;
+ return next;
+}
+
+/*
+TiXmlAttribute* TiXmlAttribute::Next()
+{
+ // We are using knowledge of the sentinel. The sentinel
+ // have a value or name.
+ if ( next->value.empty() && next->name.empty() )
+ return 0;
+ return next;
+}
+*/
+
+const TiXmlAttribute* TiXmlAttribute::Previous() const
+{
+ // We are using knowledge of the sentinel. The sentinel
+ // have a value or name.
+ if ( prev->value.empty() && prev->name.empty() )
+ return 0;
+ return prev;
+}
+
+/*
+TiXmlAttribute* TiXmlAttribute::Previous()
+{
+ // We are using knowledge of the sentinel. The sentinel
+ // have a value or name.
+ if ( prev->value.empty() && prev->name.empty() )
+ return 0;
+ return prev;
+}
+*/
+
+void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const
+{
+ TIXML_STRING n, v;
+
+ EncodeString( name, &n );
+ EncodeString( value, &v );
+
+ if (value.find ('\"') == TIXML_STRING::npos) {
+ if ( cfile ) {
+ fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() );
+ }
+ if ( str ) {
+ (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\"";
+ }
+ }
+ else {
+ if ( cfile ) {
+ fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() );
+ }
+ if ( str ) {
+ (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'";
+ }
+ }
+}
+
+
+int TiXmlAttribute::QueryIntValue( int* ival ) const
+{
+ if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 )
+ return TIXML_SUCCESS;
+ return TIXML_WRONG_TYPE;
+}
+
+int TiXmlAttribute::QueryDoubleValue( double* dval ) const
+{
+ if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 )
+ return TIXML_SUCCESS;
+ return TIXML_WRONG_TYPE;
+}
+
+void TiXmlAttribute::SetIntValue( int _value )
+{
+ char buf [64];
+ #if defined(TIXML_SNPRINTF)
+ TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value);
+ #else
+ sprintf (buf, "%d", _value);
+ #endif
+ SetValue (buf);
+}
+
+void TiXmlAttribute::SetDoubleValue( double _value )
+{
+ char buf [256];
+ #if defined(TIXML_SNPRINTF)
+ TIXML_SNPRINTF( buf, sizeof(buf), "%f", _value);
+ #else
+ sprintf (buf, "%f", _value);
+ #endif
+ SetValue (buf);
+}
+
+int TiXmlAttribute::IntValue() const
+{
+ return atoi (value.c_str ());
+}
+
+double TiXmlAttribute::DoubleValue() const
+{
+ return atof (value.c_str ());
+}
+
+
+TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT )
+{
+ copy.CopyTo( this );
+}
+
+
+void TiXmlComment::operator=( const TiXmlComment& base )
+{
+ Clear();
+ base.CopyTo( this );
+}
+
+
+void TiXmlComment::Print( FILE* cfile, int depth ) const
+{
+ assert( cfile );
+ for ( int i=0; i<depth; i++ )
+ {
+ fprintf( cfile, " " );
+ }
+ fprintf( cfile, "<!--%s-->", value.c_str() );
+}
+
+
+void TiXmlComment::CopyTo( TiXmlComment* target ) const
+{
+ TiXmlNode::CopyTo( target );
+}
+
+
+bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const
+{
+ return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlComment::Clone() const
+{
+ TiXmlComment* clone = new TiXmlComment();
+
+ if ( !clone )
+ return 0;
+
+ CopyTo( clone );
+ return clone;
+}
+
+
+void TiXmlText::Print( FILE* cfile, int depth ) const
+{
+ assert( cfile );
+ if ( cdata )
+ {
+ int i;
+ fprintf( cfile, "\n" );
+ for ( i=0; i<depth; i++ ) {
+ fprintf( cfile, " " );
+ }
+ fprintf( cfile, "<![CDATA[%s]]>\n", value.c_str() ); // unformatted output
+ }
+ else
+ {
+ TIXML_STRING buffer;
+ EncodeString( value, &buffer );
+ fprintf( cfile, "%s", buffer.c_str() );
+ }
+}
+
+
+void TiXmlText::CopyTo( TiXmlText* target ) const
+{
+ TiXmlNode::CopyTo( target );
+ target->cdata = cdata;
+}
+
+
+bool TiXmlText::Accept( TiXmlVisitor* visitor ) const
+{
+ return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlText::Clone() const
+{
+ TiXmlText* clone = 0;
+ clone = new TiXmlText( "" );
+
+ if ( !clone )
+ return 0;
+
+ CopyTo( clone );
+ return clone;
+}
+
+
+TiXmlDeclaration::TiXmlDeclaration( const char * _version,
+ const char * _encoding,
+ const char * _standalone )
+ : TiXmlNode( TiXmlNode::DECLARATION )
+{
+ version = _version;
+ encoding = _encoding;
+ standalone = _standalone;
+}
+
+
+#ifdef TIXML_USE_STL
+TiXmlDeclaration::TiXmlDeclaration( const std::string& _version,
+ const std::string& _encoding,
+ const std::string& _standalone )
+ : TiXmlNode( TiXmlNode::DECLARATION )
+{
+ version = _version;
+ encoding = _encoding;
+ standalone = _standalone;
+}
+#endif
+
+
+TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy )
+ : TiXmlNode( TiXmlNode::DECLARATION )
+{
+ copy.CopyTo( this );
+}
+
+
+void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy )
+{
+ Clear();
+ copy.CopyTo( this );
+}
+
+
+void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const
+{
+ if ( cfile ) fprintf( cfile, "<?xml " );
+ if ( str ) (*str) += "<?xml ";
+
+ if ( !version.empty() ) {
+ if ( cfile ) fprintf (cfile, "version=\"%s\" ", version.c_str ());
+ if ( str ) { (*str) += "version=\""; (*str) += version; (*str) += "\" "; }
+ }
+ if ( !encoding.empty() ) {
+ if ( cfile ) fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ());
+ if ( str ) { (*str) += "encoding=\""; (*str) += encoding; (*str) += "\" "; }
+ }
+ if ( !standalone.empty() ) {
+ if ( cfile ) fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ());
+ if ( str ) { (*str) += "standalone=\""; (*str) += standalone; (*str) += "\" "; }
+ }
+ if ( cfile ) fprintf( cfile, "?>" );
+ if ( str ) (*str) += "?>";
+}
+
+
+void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const
+{
+ TiXmlNode::CopyTo( target );
+
+ target->version = version;
+ target->encoding = encoding;
+ target->standalone = standalone;
+}
+
+
+bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const
+{
+ return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlDeclaration::Clone() const
+{
+ TiXmlDeclaration* clone = new TiXmlDeclaration();
+
+ if ( !clone )
+ return 0;
+
+ CopyTo( clone );
+ return clone;
+}
+
+
+void TiXmlUnknown::Print( FILE* cfile, int depth ) const
+{
+ for ( int i=0; i<depth; i++ )
+ fprintf( cfile, " " );
+ fprintf( cfile, "<%s>", value.c_str() );
+}
+
+
+void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const
+{
+ TiXmlNode::CopyTo( target );
+}
+
+
+bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const
+{
+ return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlUnknown::Clone() const
+{
+ TiXmlUnknown* clone = new TiXmlUnknown();
+
+ if ( !clone )
+ return 0;
+
+ CopyTo( clone );
+ return clone;
+}
+
+
+TiXmlAttributeSet::TiXmlAttributeSet()
+{
+ sentinel.next = &sentinel;
+ sentinel.prev = &sentinel;
+}
+
+
+TiXmlAttributeSet::~TiXmlAttributeSet()
+{
+ assert( sentinel.next == &sentinel );
+ assert( sentinel.prev == &sentinel );
+}
+
+
+void TiXmlAttributeSet::Add( TiXmlAttribute* addMe )
+{
+ #ifdef TIXML_USE_STL
+ assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set.
+ #else
+ assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set.
+ #endif
+
+ addMe->next = &sentinel;
+ addMe->prev = sentinel.prev;
+
+ sentinel.prev->next = addMe;
+ sentinel.prev = addMe;
+}
+
+void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )
+{
+ TiXmlAttribute* node;
+
+ for( node = sentinel.next; node != &sentinel; node = node->next )
+ {
+ if ( node == removeMe )
+ {
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ node->next = 0;
+ node->prev = 0;
+ return;
+ }
+ }
+ assert( 0 ); // we tried to remove a non-linked attribute.
+}
+
+
+#ifdef TIXML_USE_STL
+const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const
+{
+ for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
+ {
+ if ( node->name == name )
+ return node;
+ }
+ return 0;
+}
+
+/*
+TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name )
+{
+ for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
+ {
+ if ( node->name == name )
+ return node;
+ }
+ return 0;
+}
+*/
+#endif
+
+
+const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const
+{
+ for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
+ {
+ if ( strcmp( node->name.c_str(), name ) == 0 )
+ return node;
+ }
+ return 0;
+}
+
+/*
+TiXmlAttribute* TiXmlAttributeSet::Find( const char* name )
+{
+ for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
+ {
+ if ( strcmp( node->name.c_str(), name ) == 0 )
+ return node;
+ }
+ return 0;
+}
+*/
+
+#ifdef TIXML_USE_STL
+std::istream& operator>> (std::istream & in, TiXmlNode & base)
+{
+ TIXML_STRING tag;
+ tag.reserve( 8 * 1000 );
+ base.StreamIn( &in, &tag );
+
+ base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING );
+ return in;
+}
+#endif
+
+
+#ifdef TIXML_USE_STL
+std::ostream& operator<< (std::ostream & out, const TiXmlNode & base)
+{
+ TiXmlPrinter printer;
+ printer.SetStreamPrinting();
+ base.Accept( &printer );
+ out << printer.Str();
+
+ return out;
+}
+
+
+std::string& operator<< (std::string& out, const TiXmlNode& base )
+{
+ TiXmlPrinter printer;
+ printer.SetStreamPrinting();
+ base.Accept( &printer );
+ out.append( printer.Str() );
+
+ return out;
+}
+#endif
+
+
+TiXmlHandle TiXmlHandle::FirstChild() const
+{
+ if ( node )
+ {
+ TiXmlNode* child = node->FirstChild();
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const
+{
+ if ( node )
+ {
+ TiXmlNode* child = node->FirstChild( value );
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::FirstChildElement() const
+{
+ if ( node )
+ {
+ TiXmlElement* child = node->FirstChildElement();
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const
+{
+ if ( node )
+ {
+ TiXmlElement* child = node->FirstChildElement( value );
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::Child( int count ) const
+{
+ if ( node )
+ {
+ int i;
+ TiXmlNode* child = node->FirstChild();
+ for ( i=0;
+ child && i<count;
+ child = child->NextSibling(), ++i )
+ {
+ // nothing
+ }
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const
+{
+ if ( node )
+ {
+ int i;
+ TiXmlNode* child = node->FirstChild( value );
+ for ( i=0;
+ child && i<count;
+ child = child->NextSibling( value ), ++i )
+ {
+ // nothing
+ }
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::ChildElement( int count ) const
+{
+ if ( node )
+ {
+ int i;
+ TiXmlElement* child = node->FirstChildElement();
+ for ( i=0;
+ child && i<count;
+ child = child->NextSiblingElement(), ++i )
+ {
+ // nothing
+ }
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const
+{
+ if ( node )
+ {
+ int i;
+ TiXmlElement* child = node->FirstChildElement( value );
+ for ( i=0;
+ child && i<count;
+ child = child->NextSiblingElement( value ), ++i )
+ {
+ // nothing
+ }
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+bool TiXmlPrinter::VisitEnter( const TiXmlDocument& )
+{
+ return true;
+}
+
+bool TiXmlPrinter::VisitExit( const TiXmlDocument& )
+{
+ return true;
+}
+
+bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute )
+{
+ DoIndent();
+ buffer += "<";
+ buffer += element.Value();
+
+ for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() )
+ {
+ buffer += " ";
+ attrib->Print( 0, 0, &buffer );
+ }
+
+ if ( !element.FirstChild() )
+ {
+ buffer += " />";
+ DoLineBreak();
+ }
+ else
+ {
+ buffer += ">";
+ if ( element.FirstChild()->ToText()
+ && element.LastChild() == element.FirstChild()
+ && element.FirstChild()->ToText()->CDATA() == false )
+ {
+ simpleTextPrint = true;
+ // no DoLineBreak()!
+ }
+ else
+ {
+ DoLineBreak();
+ }
+ }
+ ++depth;
+ return true;
+}
+
+
+bool TiXmlPrinter::VisitExit( const TiXmlElement& element )
+{
+ --depth;
+ if ( !element.FirstChild() )
+ {
+ // nothing.
+ }
+ else
+ {
+ if ( simpleTextPrint )
+ {
+ simpleTextPrint = false;
+ }
+ else
+ {
+ DoIndent();
+ }
+ buffer += "</";
+ buffer += element.Value();
+ buffer += ">";
+ DoLineBreak();
+ }
+ return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlText& text )
+{
+ if ( text.CDATA() )
+ {
+ DoIndent();
+ buffer += "<![CDATA[";
+ buffer += text.Value();
+ buffer += "]]>";
+ DoLineBreak();
+ }
+ else if ( simpleTextPrint )
+ {
+ TIXML_STRING str;
+ TiXmlBase::EncodeString( text.ValueTStr(), &str );
+ buffer += str;
+ }
+ else
+ {
+ DoIndent();
+ TIXML_STRING str;
+ TiXmlBase::EncodeString( text.ValueTStr(), &str );
+ buffer += str;
+ DoLineBreak();
+ }
+ return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration )
+{
+ DoIndent();
+ declaration.Print( 0, 0, &buffer );
+ DoLineBreak();
+ return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlComment& comment )
+{
+ DoIndent();
+ buffer += "<!--";
+ buffer += comment.Value();
+ buffer += "-->";
+ DoLineBreak();
+ return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown )
+{
+ DoIndent();
+ buffer += "<";
+ buffer += unknown.Value();
+ buffer += ">";
+ DoLineBreak();
+ return true;
+}
+
diff --git a/guilib/tinyXML/tinyxml.h b/guilib/tinyXML/tinyxml.h
new file mode 100644
index 0000000000..a1619d864a
--- /dev/null
+++ b/guilib/tinyXML/tinyxml.h
@@ -0,0 +1,1830 @@
+/*
+www.sourceforge.net/projects/tinyxml
+Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+
+#ifndef TINYXML_INCLUDED
+#define TINYXML_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning( push )
+#pragma warning( disable : 4530 )
+#pragma warning( disable : 4786 )
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+// Help out windows (but don't mess up OSX):
+#if defined( _WIN32PC) || defined( _WIN32 ) || defined(WIN32)
+#if defined( _DEBUG ) && !defined( DEBUG )
+#define DEBUG
+#endif
+#endif
+
+#ifndef TIXML_USE_STL
+#define TIXML_USE_STL
+#endif
+
+#ifndef HAS_ICONV
+#define HAS_ICONV
+#endif
+
+#ifdef TIXML_USE_STL
+ #include <string>
+ #include <iostream>
+ #include <sstream>
+ #define TIXML_STRING std::string
+#else
+ #include "tinystr.h"
+ #define TIXML_STRING TiXmlString
+#endif
+
+#ifdef HAS_ICONV
+#if defined( _WIN32PC) || defined( _WIN32 ) || defined(WIN32)
+#include "lib/libiconv/iconv.h"
+#else
+#include <iconv.h>
+#endif
+#endif
+
+// Deprecated library function hell. Compilers want to use the
+// new safe versions. This probably doesn't fully address the problem,
+// but it gets closer. There are too many compilers for me to fully
+// test. If you get compilation troubles, undefine TIXML_SAFE
+#define TIXML_SAFE
+
+#ifdef TIXML_SAFE
+ #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
+ // Microsoft visual studio, version 2005 and higher.
+ #define TIXML_SNPRINTF _snprintf_s
+ #define TIXML_SNSCANF _snscanf_s
+ #define TIXML_SSCANF sscanf_s
+ #elif defined(_MSC_VER) && (_MSC_VER >= 1200 )
+ // Microsoft visual studio, version 6 and higher.
+ //#pragma message( "Using _sn* functions." )
+ #define TIXML_SNPRINTF _snprintf
+ #define TIXML_SNSCANF _snscanf
+ #define TIXML_SSCANF sscanf
+ #elif defined(__GNUC__) && (__GNUC__ >= 3 )
+ // GCC version 3 and higher.s
+ //#warning( "Using sn* functions." )
+ #define TIXML_SNPRINTF snprintf
+ #define TIXML_SNSCANF snscanf
+ #define TIXML_SSCANF sscanf
+ #else
+ #define TIXML_SSCANF sscanf
+ #endif
+#endif
+
+class TiXmlDocument;
+class TiXmlElement;
+class TiXmlComment;
+class TiXmlUnknown;
+class TiXmlAttribute;
+class TiXmlText;
+class TiXmlDeclaration;
+class TiXmlParsingData;
+
+const int TIXML_MAJOR_VERSION = 2;
+const int TIXML_MINOR_VERSION = 5;
+const int TIXML_PATCH_VERSION = 3;
+
+/* Internal structure for tracking location of items
+ in the XML file.
+*/
+struct TiXmlCursor
+{
+ TiXmlCursor() { Clear(); }
+ void Clear() { row = col = -1; }
+
+ int row; // 0 based.
+ int col; // 0 based.
+};
+
+
+/**
+ If you call the Accept() method, it requires being passed a TiXmlVisitor
+ class to handle callbacks. For nodes that contain other nodes (Document, Element)
+ you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
+ are simple called with Visit().
+
+ If you return 'true' from a Visit method, recursive parsing will continue. If you return
+ false, <b>no children of this node or its sibilings</b> will be Visited.
+
+ All flavors of Visit methods have a default implementation that returns 'true' (continue
+ visiting). You need to only override methods that are interesting to you.
+
+ Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
+
+ You should never change the document from a callback.
+
+ @sa TiXmlNode::Accept()
+*/
+class TiXmlVisitor
+{
+public:
+ virtual ~TiXmlVisitor() {}
+
+ /// Visit a document.
+ virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; }
+ /// Visit a document.
+ virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; }
+
+ /// Visit an element.
+ virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; }
+ /// Visit an element.
+ virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; }
+
+ /// Visit a declaration
+ virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; }
+ /// Visit a text node
+ virtual bool Visit( const TiXmlText& /*text*/ ) { return true; }
+ /// Visit a comment node
+ virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; }
+ /// Visit an unknow node
+ virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; }
+};
+
+// Only used by Attribute::Query functions
+enum
+{
+ TIXML_SUCCESS,
+ TIXML_NO_ATTRIBUTE,
+ TIXML_WRONG_TYPE
+};
+
+
+// Used by the parsing routines.
+enum TiXmlEncoding
+{
+ TIXML_ENCODING_UNKNOWN,
+ TIXML_ENCODING_UTF8,
+ TIXML_ENCODING_LEGACY
+};
+
+const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN;
+
+/** TiXmlBase is a base class for every class in TinyXml.
+ It does little except to establish that TinyXml classes
+ can be printed and provide some utility functions.
+
+ In XML, the document and elements can contain
+ other elements and other types of nodes.
+
+ @verbatim
+ A Document can contain: Element (container or leaf)
+ Comment (leaf)
+ Unknown (leaf)
+ Declaration( leaf )
+
+ An Element can contain: Element (container or leaf)
+ Text (leaf)
+ Attributes (not on tree)
+ Comment (leaf)
+ Unknown (leaf)
+
+ A Decleration contains: Attributes (not on tree)
+ @endverbatim
+*/
+class TiXmlBase
+{
+ friend class TiXmlNode;
+ friend class TiXmlElement;
+ friend class TiXmlDocument;
+
+public:
+ TiXmlBase() : userData(0) {}
+ virtual ~TiXmlBase() {}
+
+ /** All TinyXml classes can print themselves to a filestream
+ or the string class (TiXmlString in non-STL mode, std::string
+ in STL mode.) Either or both cfile and str can be null.
+
+ This is a formatted print, and will insert
+ tabs and newlines.
+
+ (For an unformatted stream, use the << operator.)
+ */
+ virtual void Print( FILE* cfile, int depth ) const = 0;
+
+ /** The world does not agree on whether white space should be kept or
+ not. In order to make everyone happy, these global, static functions
+ are provided to set whether or not TinyXml will condense all white space
+ into a single space or not. The default is to condense. Note changing this
+ value is not thread safe.
+ */
+ static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; }
+
+ /// Return the current white space setting.
+ static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; }
+
+ /** Return the position, in the original source file, of this node or attribute.
+ The row and column are 1-based. (That is the first row and first column is
+ 1,1). If the returns values are 0 or less, then the parser does not have
+ a row and column value.
+
+ Generally, the row and column value will be set when the TiXmlDocument::Load(),
+ TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set
+ when the DOM was created from operator>>.
+
+ The values reflect the initial load. Once the DOM is modified programmatically
+ (by adding or changing nodes and attributes) the new values will NOT update to
+ reflect changes in the document.
+
+ There is a minor performance cost to computing the row and column. Computation
+ can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value.
+
+ @sa TiXmlDocument::SetTabSize()
+ */
+ int Row() const { return location.row + 1; }
+ int Column() const { return location.col + 1; } ///< See Row()
+
+ void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data.
+ void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data.
+ const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data.
+
+ // Table that returs, for a given lead byte, the total number of bytes
+ // in the UTF-8 sequence.
+ static const int utf8ByteTable[256];
+
+ virtual const char* Parse( const char* p,
+ TiXmlParsingData* data,
+ TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0;
+
+ /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc,
+ or they will be transformed into entities!
+ */
+ static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out );
+
+ enum
+ {
+ TIXML_NO_ERROR = 0,
+ TIXML_ERROR,
+ TIXML_ERROR_OPENING_FILE,
+ TIXML_ERROR_OUT_OF_MEMORY,
+ TIXML_ERROR_PARSING_ELEMENT,
+ TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME,
+ TIXML_ERROR_READING_ELEMENT_VALUE,
+ TIXML_ERROR_READING_ATTRIBUTES,
+ TIXML_ERROR_PARSING_EMPTY,
+ TIXML_ERROR_READING_END_TAG,
+ TIXML_ERROR_PARSING_UNKNOWN,
+ TIXML_ERROR_PARSING_COMMENT,
+ TIXML_ERROR_PARSING_DECLARATION,
+ TIXML_ERROR_DOCUMENT_EMPTY,
+ TIXML_ERROR_EMBEDDED_NULL,
+ TIXML_ERROR_PARSING_CDATA,
+ TIXML_ERROR_DOCUMENT_TOP_ONLY,
+
+ TIXML_ERROR_STRING_COUNT
+ };
+
+protected:
+
+#ifdef HAS_ICONV
+ static void ConvertToUtf8(TiXmlDocument* document, TIXML_STRING* text);
+#endif
+
+ static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding );
+ inline static bool IsWhiteSpace( char c )
+ {
+ return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' );
+ }
+ inline static bool IsWhiteSpace( int c )
+ {
+ if ( c < 256 )
+ return IsWhiteSpace( (char) c );
+ return false; // Again, only truly correct for English/Latin...but usually works.
+ }
+
+ #ifdef TIXML_USE_STL
+ static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag );
+ static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag );
+ #endif
+
+ /* Reads an XML name into the string provided. Returns
+ a pointer just past the last character of the name,
+ or 0 if the function has an error.
+ */
+ static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding );
+
+ /* Reads text. Returns a pointer past the given end tag.
+ Wickedly complex options, but it keeps the (sensitive) code in one place.
+ */
+ static const char* ReadText( const char* in, // where to start
+ TIXML_STRING* text, // the string read
+ bool ignoreWhiteSpace, // whether to keep the white space
+ const char* endTag, // what ends this text
+ bool ignoreCase, // whether to ignore case in the end tag
+ TiXmlEncoding encoding ); // the current encoding
+
+ // If an entity has been found, transform it into a character.
+ static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding );
+
+ // Get a character, while interpreting entities.
+ // The length can be from 0 to 4 bytes.
+ inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding )
+ {
+ assert( p );
+ if ( encoding == TIXML_ENCODING_UTF8 )
+ {
+ *length = utf8ByteTable[ *((const unsigned char*)p) ];
+ assert( *length >= 0 && *length < 5 );
+ }
+ else
+ {
+ *length = 1;
+ }
+
+ if ( *length == 1 )
+ {
+ if ( *p == '&' )
+ return GetEntity( p, _value, length, encoding );
+ *_value = *p;
+ return p+1;
+ }
+ else if ( *length )
+ {
+ //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe),
+ // and the null terminator isn't needed
+ for( int i=0; p[i] && i<*length; ++i ) {
+ _value[i] = p[i];
+ }
+ return p + (*length);
+ }
+ else
+ {
+ // Not valid text.
+ return 0;
+ }
+ }
+
+ // Return true if the next characters in the stream are any of the endTag sequences.
+ // Ignore case only works for english, and should only be relied on when comparing
+ // to English words: StringEqual( p, "version", true ) is fine.
+ static bool StringEqual( const char* p,
+ const char* endTag,
+ bool ignoreCase,
+ TiXmlEncoding encoding );
+
+ static const char* errorString[ TIXML_ERROR_STRING_COUNT ];
+
+ TiXmlCursor location;
+
+ /// Field containing a generic user pointer
+ void* userData;
+
+ // None of these methods are reliable for any language except English.
+ // Good for approximation, not great for accuracy.
+ static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding );
+ static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding );
+ inline static int ToLower( int v, TiXmlEncoding encoding )
+ {
+ if ( encoding == TIXML_ENCODING_UTF8 )
+ {
+ if ( v < 128 ) return tolower( v );
+ return v;
+ }
+ else
+ {
+ return tolower( v );
+ }
+ }
+ static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
+
+private:
+ TiXmlBase( const TiXmlBase& ); // not implemented.
+ void operator=( const TiXmlBase& base ); // not allowed.
+
+ struct Entity
+ {
+ const char* str;
+ unsigned int strLength;
+ char chr;
+ };
+ enum
+ {
+ NUM_ENTITY = 5,
+ MAX_ENTITY_LENGTH = 6
+
+ };
+ static Entity entity[ NUM_ENTITY ];
+ static bool condenseWhiteSpace;
+};
+
+
+/** The parent class for everything in the Document Object Model.
+ (Except for attributes).
+ Nodes have siblings, a parent, and children. A node can be
+ in a document, or stand on its own. The type of a TiXmlNode
+ can be queried, and it can be cast to its more defined type.
+*/
+class TiXmlNode : public TiXmlBase
+{
+ friend class TiXmlDocument;
+ friend class TiXmlElement;
+
+public:
+ #ifdef TIXML_USE_STL
+
+ /** An input stream operator, for every class. Tolerant of newlines and
+ formatting, but doesn't expect them.
+ */
+ friend std::istream& operator >> (std::istream& in, TiXmlNode& base);
+
+ /** An output stream operator, for every class. Note that this outputs
+ without any newlines or formatting, as opposed to Print(), which
+ includes tabs and new lines.
+
+ The operator<< and operator>> are not completely symmetric. Writing
+ a node to a stream is very well defined. You'll get a nice stream
+ of output, without any extra whitespace or newlines.
+
+ But reading is not as well defined. (As it always is.) If you create
+ a TiXmlElement (for example) and read that from an input stream,
+ the text needs to define an element or junk will result. This is
+ true of all input streams, but it's worth keeping in mind.
+
+ A TiXmlDocument will read nodes until it reads a root element, and
+ all the children of that root element.
+ */
+ friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base);
+
+ /// Appends the XML node or attribute to a std::string.
+ friend std::string& operator<< (std::string& out, const TiXmlNode& base );
+
+ #endif
+
+ /** The types of XML nodes supported by TinyXml. (All the
+ unsupported types are picked up by UNKNOWN.)
+ */
+ enum NodeType
+ {
+ DOCUMENT,
+ ELEMENT,
+ COMMENT,
+ UNKNOWN,
+ TEXT,
+ DECLARATION,
+ TYPECOUNT
+ };
+
+ virtual ~TiXmlNode();
+
+ /** The meaning of 'value' changes for the specific type of
+ TiXmlNode.
+ @verbatim
+ Document: filename of the xml file
+ Element: name of the element
+ Comment: the comment text
+ Unknown: the tag contents
+ Text: the text string
+ @endverbatim
+
+ The subclasses will wrap this function.
+ */
+ const char *Value() const { return value.c_str (); }
+
+ #ifdef TIXML_USE_STL
+ /** Return Value() as a std::string. If you only use STL,
+ this is more efficient than calling Value().
+ Only available in STL mode.
+ */
+ const std::string& ValueStr() const { return value; }
+ #endif
+
+ const TIXML_STRING& ValueTStr() const { return value; }
+
+ /** Changes the value of the node. Defined as:
+ @verbatim
+ Document: filename of the xml file
+ Element: name of the element
+ Comment: the comment text
+ Unknown: the tag contents
+ Text: the text string
+ @endverbatim
+ */
+ void SetValue(const char * _value) { value = _value;}
+
+ #ifdef TIXML_USE_STL
+ /// STL std::string form.
+ void SetValue( const std::string& _value ) { value = _value; }
+ #endif
+
+ /// Delete all the children of this node. Does not affect 'this'.
+ void Clear();
+
+ /// One step up the DOM.
+ TiXmlNode* Parent() { return parent; }
+ const TiXmlNode* Parent() const { return parent; }
+
+ const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children.
+ TiXmlNode* FirstChild() { return firstChild; }
+ const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found.
+ /// The first child of this node with the matching 'value'. Will be null if none found.
+ TiXmlNode* FirstChild( const char * _value ) {
+ // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe)
+ // call the method, cast the return back to non-const.
+ return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value ));
+ }
+ const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children.
+ TiXmlNode* LastChild() { return lastChild; }
+
+ const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children.
+ TiXmlNode* LastChild( const char * _value ) {
+ return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value ));
+ }
+
+ #ifdef TIXML_USE_STL
+ const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form.
+ TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form.
+ const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form.
+ TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form.
+ #endif
+
+ /** An alternate way to walk the children of a node.
+ One way to iterate over nodes is:
+ @verbatim
+ for( child = parent->FirstChild(); child; child = child->NextSibling() )
+ @endverbatim
+
+ IterateChildren does the same thing with the syntax:
+ @verbatim
+ child = 0;
+ while( child = parent->IterateChildren( child ) )
+ @endverbatim
+
+ IterateChildren takes the previous child as input and finds
+ the next one. If the previous child is null, it returns the
+ first. IterateChildren will return null when done.
+ */
+ const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const;
+ TiXmlNode* IterateChildren( const TiXmlNode* previous ) {
+ return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) );
+ }
+
+ /// This flavor of IterateChildren searches for children with a particular 'value'
+ const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const;
+ TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) {
+ return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) );
+ }
+
+ #ifdef TIXML_USE_STL
+ const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form.
+ TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form.
+ #endif
+
+ /** Add a new node related to this. Adds a child past the LastChild.
+ Returns a pointer to the new object or NULL if an error occured.
+ */
+ TiXmlNode* InsertEndChild( const TiXmlNode& addThis );
+
+
+ /** Add a new node related to this. Adds a child past the LastChild.
+
+ NOTE: the node to be added is passed by pointer, and will be
+ henceforth owned (and deleted) by tinyXml. This method is efficient
+ and avoids an extra copy, but should be used with care as it
+ uses a different memory model than the other insert functions.
+
+ @sa InsertEndChild
+ */
+ TiXmlNode* LinkEndChild( TiXmlNode* addThis );
+
+ /** Add a new node related to this. Adds a child before the specified child.
+ Returns a pointer to the new object or NULL if an error occured.
+ */
+ TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis );
+
+ /** Add a new node related to this. Adds a child after the specified child.
+ Returns a pointer to the new object or NULL if an error occured.
+ */
+ TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis );
+
+ /** Replace a child of this node.
+ Returns a pointer to the new object or NULL if an error occured.
+ */
+ TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis );
+
+ /// Delete a child of this node.
+ bool RemoveChild( TiXmlNode* removeThis );
+
+ /// Navigate to a sibling node.
+ const TiXmlNode* PreviousSibling() const { return prev; }
+ TiXmlNode* PreviousSibling() { return prev; }
+
+ /// Navigate to a sibling node.
+ const TiXmlNode* PreviousSibling( const char * ) const;
+ TiXmlNode* PreviousSibling( const char *_prev ) {
+ return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) );
+ }
+
+ #ifdef TIXML_USE_STL
+ const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form.
+ TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form.
+ const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form.
+ TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form.
+ #endif
+
+ /// Navigate to a sibling node.
+ const TiXmlNode* NextSibling() const { return next; }
+ TiXmlNode* NextSibling() { return next; }
+
+ /// Navigate to a sibling node with the given 'value'.
+ const TiXmlNode* NextSibling( const char * ) const;
+ TiXmlNode* NextSibling( const char* _next ) {
+ return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) );
+ }
+
+ /** Convenience function to get through elements.
+ Calls NextSibling and ToElement. Will skip all non-Element
+ nodes. Returns 0 if there is not another element.
+ */
+ const TiXmlElement* NextSiblingElement() const;
+ TiXmlElement* NextSiblingElement() {
+ return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() );
+ }
+
+ /** Convenience function to get through elements.
+ Calls NextSibling and ToElement. Will skip all non-Element
+ nodes. Returns 0 if there is not another element.
+ */
+ const TiXmlElement* NextSiblingElement( const char * ) const;
+ TiXmlElement* NextSiblingElement( const char *_next ) {
+ return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) );
+ }
+
+ #ifdef TIXML_USE_STL
+ const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form.
+ TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form.
+ #endif
+
+ /// Convenience function to get through elements.
+ const TiXmlElement* FirstChildElement() const;
+ TiXmlElement* FirstChildElement() {
+ return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() );
+ }
+
+ /// Convenience function to get through elements.
+ const TiXmlElement* FirstChildElement( const char * _value ) const;
+ TiXmlElement* FirstChildElement( const char * _value ) {
+ return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) );
+ }
+
+ #ifdef TIXML_USE_STL
+ const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form.
+ TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form.
+ #endif
+
+ /** Query the type (as an enumerated value, above) of this node.
+ The possible types are: DOCUMENT, ELEMENT, COMMENT,
+ UNKNOWN, TEXT, and DECLARATION.
+ */
+ int Type() const { return type; }
+
+ /** Return a pointer to the Document this node lives in.
+ Returns null if not in a document.
+ */
+ const TiXmlDocument* GetDocument() const;
+ TiXmlDocument* GetDocument() {
+ return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() );
+ }
+
+ /// Returns true if this node has no children.
+ bool NoChildren() const { return !firstChild; }
+
+ virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+
+ virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+
+ /** Create an exact duplicate of this node and return it. The memory must be deleted
+ by the caller.
+ */
+ virtual TiXmlNode* Clone() const = 0;
+
+ /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the
+ XML tree will be conditionally visited and the host will be called back
+ via the TiXmlVisitor interface.
+
+ This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
+ the XML for the callbacks, so the performance of TinyXML is unchanged by using this
+ interface versus any other.)
+
+ The interface has been based on ideas from:
+
+ - http://www.saxproject.org/
+ - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
+
+ Which are both good references for "visiting".
+
+ An example of using Accept():
+ @verbatim
+ TiXmlPrinter printer;
+ tinyxmlDoc.Accept( &printer );
+ const char* xmlcstr = printer.CStr();
+ @endverbatim
+ */
+ virtual bool Accept( TiXmlVisitor* visitor ) const = 0;
+
+protected:
+ TiXmlNode( NodeType _type );
+
+ // Copy to the allocated object. Shared functionality between Clone, Copy constructor,
+ // and the assignment operator.
+ void CopyTo( TiXmlNode* target ) const;
+
+ #ifdef TIXML_USE_STL
+ // The real work of the input operator.
+ virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0;
+ #endif
+
+ // Figure out what is at *p, and parse it. Returns null if it is not an xml node.
+ TiXmlNode* Identify( const char* start, TiXmlEncoding encoding );
+
+ TiXmlNode* parent;
+ NodeType type;
+
+ TiXmlNode* firstChild;
+ TiXmlNode* lastChild;
+
+ TIXML_STRING value;
+
+ TiXmlNode* prev;
+ TiXmlNode* next;
+
+private:
+ TiXmlNode( const TiXmlNode& ); // not implemented.
+ void operator=( const TiXmlNode& base ); // not allowed.
+};
+
+
+/** An attribute is a name-value pair. Elements have an arbitrary
+ number of attributes, each with a unique name.
+
+ @note The attributes are not TiXmlNodes, since they are not
+ part of the tinyXML document object model. There are other
+ suggested ways to look at this problem.
+*/
+class TiXmlAttribute : public TiXmlBase
+{
+ friend class TiXmlAttributeSet;
+
+public:
+ /// Construct an empty attribute.
+ TiXmlAttribute() : TiXmlBase()
+ {
+ document = 0;
+ prev = next = 0;
+ }
+
+ #ifdef TIXML_USE_STL
+ /// std::string constructor.
+ TiXmlAttribute( const std::string& _name, const std::string& _value )
+ {
+ name = _name;
+ value = _value;
+ document = 0;
+ prev = next = 0;
+ }
+ #endif
+
+ /// Construct an attribute with a name and value.
+ TiXmlAttribute( const char * _name, const char * _value )
+ {
+ name = _name;
+ value = _value;
+ document = 0;
+ prev = next = 0;
+ }
+
+ const char* Name() const { return name.c_str(); } ///< Return the name of this attribute.
+ const char* Value() const { return value.c_str(); } ///< Return the value of this attribute.
+ #ifdef TIXML_USE_STL
+ const std::string& ValueStr() const { return value; } ///< Return the value of this attribute.
+ #endif
+ int IntValue() const; ///< Return the value of this attribute, converted to an integer.
+ double DoubleValue() const; ///< Return the value of this attribute, converted to a double.
+
+ // Get the tinyxml string representation
+ const TIXML_STRING& NameTStr() const { return name; }
+
+ /** QueryIntValue examines the value string. It is an alternative to the
+ IntValue() method with richer error checking.
+ If the value is an integer, it is stored in 'value' and
+ the call returns TIXML_SUCCESS. If it is not
+ an integer, it returns TIXML_WRONG_TYPE.
+
+ A specialized but useful call. Note that for success it returns 0,
+ which is the opposite of almost all other TinyXml calls.
+ */
+ int QueryIntValue( int* _value ) const;
+ /// QueryDoubleValue examines the value string. See QueryIntValue().
+ int QueryDoubleValue( double* _value ) const;
+
+ void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute.
+ void SetValue( const char* _value ) { value = _value; } ///< Set the value.
+
+ void SetIntValue( int _value ); ///< Set the value from an integer.
+ void SetDoubleValue( double _value ); ///< Set the value from a double.
+
+ #ifdef TIXML_USE_STL
+ /// STL std::string form.
+ void SetName( const std::string& _name ) { name = _name; }
+ /// STL std::string form.
+ void SetValue( const std::string& _value ) { value = _value; }
+ #endif
+
+ /// Get the next sibling attribute in the DOM. Returns null at end.
+ const TiXmlAttribute* Next() const;
+ TiXmlAttribute* Next() {
+ return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() );
+ }
+
+ /// Get the previous sibling attribute in the DOM. Returns null at beginning.
+ const TiXmlAttribute* Previous() const;
+ TiXmlAttribute* Previous() {
+ return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() );
+ }
+
+ bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; }
+ bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; }
+ bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; }
+
+ /* Attribute parsing starts: first letter of the name
+ returns: the next char after the value end quote
+ */
+ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+ // Prints this Attribute to a FILE stream.
+ virtual void Print( FILE* cfile, int depth ) const {
+ Print( cfile, depth, 0 );
+ }
+ void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;
+
+ // [internal use]
+ // Set the document pointer so the attribute can report errors.
+ void SetDocument( TiXmlDocument* doc ) { document = doc; }
+
+private:
+ TiXmlAttribute( const TiXmlAttribute& ); // not implemented.
+ void operator=( const TiXmlAttribute& base ); // not allowed.
+
+ TiXmlDocument* document; // A pointer back to a document, for error reporting.
+ TIXML_STRING name;
+ TIXML_STRING value;
+ TiXmlAttribute* prev;
+ TiXmlAttribute* next;
+};
+
+
+/* A class used to manage a group of attributes.
+ It is only used internally, both by the ELEMENT and the DECLARATION.
+
+ The set can be changed transparent to the Element and Declaration
+ classes that use it, but NOT transparent to the Attribute
+ which has to implement a next() and previous() method. Which makes
+ it a bit problematic and prevents the use of STL.
+
+ This version is implemented with circular lists because:
+ - I like circular lists
+ - it demonstrates some independence from the (typical) doubly linked list.
+*/
+class TiXmlAttributeSet
+{
+public:
+ TiXmlAttributeSet();
+ ~TiXmlAttributeSet();
+
+ void Add( TiXmlAttribute* attribute );
+ void Remove( TiXmlAttribute* attribute );
+
+ const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
+ TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
+ const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
+ TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
+
+ const TiXmlAttribute* Find( const char* _name ) const;
+ TiXmlAttribute* Find( const char* _name ) {
+ return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) );
+ }
+ #ifdef TIXML_USE_STL
+ const TiXmlAttribute* Find( const std::string& _name ) const;
+ TiXmlAttribute* Find( const std::string& _name ) {
+ return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) );
+ }
+
+ #endif
+
+private:
+ //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element),
+ //*ME: this class must be also use a hidden/disabled copy-constructor !!!
+ TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed
+ void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute)
+
+ TiXmlAttribute sentinel;
+};
+
+
+/** The element is a container class. It has a value, the element name,
+ and can contain other elements, text, comments, and unknowns.
+ Elements also contain an arbitrary number of attributes.
+*/
+class TiXmlElement : public TiXmlNode
+{
+public:
+ /// Construct an element.
+ TiXmlElement (const char * in_value);
+
+ #ifdef TIXML_USE_STL
+ /// std::string constructor.
+ TiXmlElement( const std::string& _value );
+ #endif
+
+ TiXmlElement( const TiXmlElement& );
+
+ void operator=( const TiXmlElement& base );
+
+ virtual ~TiXmlElement();
+
+ /** Given an attribute name, Attribute() returns the value
+ for the attribute of that name, or null if none exists.
+ */
+ const char* Attribute( const char* name ) const;
+
+ /** Given an attribute name, Attribute() returns the value
+ for the attribute of that name, or null if none exists.
+ If the attribute exists and can be converted to an integer,
+ the integer value will be put in the return 'i', if 'i'
+ is non-null.
+ */
+ const char* Attribute( const char* name, int* i ) const;
+
+ /** Given an attribute name, Attribute() returns the value
+ for the attribute of that name, or null if none exists.
+ If the attribute exists and can be converted to an double,
+ the double value will be put in the return 'd', if 'd'
+ is non-null.
+ */
+ const char* Attribute( const char* name, double* d ) const;
+
+ /** QueryIntAttribute examines the attribute - it is an alternative to the
+ Attribute() method with richer error checking.
+ If the attribute is an integer, it is stored in 'value' and
+ the call returns TIXML_SUCCESS. If it is not
+ an integer, it returns TIXML_WRONG_TYPE. If the attribute
+ does not exist, then TIXML_NO_ATTRIBUTE is returned.
+ */
+ int QueryIntAttribute( const char* name, int* _value ) const;
+ /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute().
+ int QueryDoubleAttribute( const char* name, double* _value ) const;
+ /// QueryFloatAttribute examines the attribute - see QueryIntAttribute().
+ int QueryFloatAttribute( const char* name, float* _value ) const {
+ double d;
+ int result = QueryDoubleAttribute( name, &d );
+ if ( result == TIXML_SUCCESS ) {
+ *_value = (float)d;
+ }
+ return result;
+ }
+
+ #ifdef TIXML_USE_STL
+ /** Template form of the attribute query which will try to read the
+ attribute into the specified type. Very easy, very powerful, but
+ be careful to make sure to call this with the correct type.
+
+ NOTE: This method doesn't work correctly for 'string' types.
+
+ @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE
+ */
+ template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const
+ {
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( !node )
+ return TIXML_NO_ATTRIBUTE;
+
+ std::stringstream sstream( node->ValueStr() );
+ sstream >> *outValue;
+ if ( !sstream.fail() )
+ return TIXML_SUCCESS;
+ return TIXML_WRONG_TYPE;
+ }
+ /*
+ This is - in theory - a bug fix for "QueryValueAtribute returns truncated std::string"
+ but template specialization is hard to get working cross-compiler. Leaving the bug for now.
+
+ // The above will fail for std::string because the space character is used as a seperator.
+ // Specialize for strings. Bug [ 1695429 ] QueryValueAtribute returns truncated std::string
+ template<> int QueryValueAttribute( const std::string& name, std::string* outValue ) const
+ {
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( !node )
+ return TIXML_NO_ATTRIBUTE;
+ *outValue = node->ValueStr();
+ return TIXML_SUCCESS;
+ }
+ */
+ #endif
+
+ /** Sets an attribute of name to a given value. The attribute
+ will be created if it does not exist, or changed if it does.
+ */
+ void SetAttribute( const char* name, const char * _value );
+
+ #ifdef TIXML_USE_STL
+ const std::string* Attribute( const std::string& name ) const;
+ const std::string* Attribute( const std::string& name, int* i ) const;
+ const std::string* Attribute( const std::string& name, double* d ) const;
+ int QueryIntAttribute( const std::string& name, int* _value ) const;
+ int QueryDoubleAttribute( const std::string& name, double* _value ) const;
+
+ /// STL std::string form.
+ void SetAttribute( const std::string& name, const std::string& _value );
+ ///< STL std::string form.
+ void SetAttribute( const std::string& name, int _value );
+ #endif
+
+ /** Sets an attribute of name to a given value. The attribute
+ will be created if it does not exist, or changed if it does.
+ */
+ void SetAttribute( const char * name, int value );
+
+ /** Sets an attribute of name to a given value. The attribute
+ will be created if it does not exist, or changed if it does.
+ */
+ void SetDoubleAttribute( const char * name, double value );
+
+ /** Deletes an attribute with the given name.
+ */
+ void RemoveAttribute( const char * name );
+ #ifdef TIXML_USE_STL
+ void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form.
+ #endif
+
+ const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element.
+ TiXmlAttribute* FirstAttribute() { return attributeSet.First(); }
+ const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element.
+ TiXmlAttribute* LastAttribute() { return attributeSet.Last(); }
+
+ /** Convenience function for easy access to the text inside an element. Although easy
+ and concise, GetText() is limited compared to getting the TiXmlText child
+ and accessing it directly.
+
+ If the first child of 'this' is a TiXmlText, the GetText()
+ returns the character string of the Text node, else null is returned.
+
+ This is a convenient method for getting the text of simple contained text:
+ @verbatim
+ <foo>This is text</foo>
+ const char* str = fooElement->GetText();
+ @endverbatim
+
+ 'str' will be a pointer to "This is text".
+
+ Note that this function can be misleading. If the element foo was created from
+ this XML:
+ @verbatim
+ <foo><b>This is text</b></foo>
+ @endverbatim
+
+ then the value of str would be null. The first child node isn't a text node, it is
+ another element. From this XML:
+ @verbatim
+ <foo>This is <b>text</b></foo>
+ @endverbatim
+ GetText() will return "This is ".
+
+ WARNING: GetText() accesses a child node - don't become confused with the
+ similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are
+ safe type casts on the referenced node.
+ */
+ const char* GetText() const;
+
+ /// Creates a new Element and returns it - the returned element is a copy.
+ virtual TiXmlNode* Clone() const;
+ // Print the Element to a FILE stream.
+ virtual void Print( FILE* cfile, int depth ) const;
+
+ /* Attribtue parsing starts: next char past '<'
+ returns: next char past '>'
+ */
+ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+ virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+ virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+ /** Walk the XML tree visiting this node and all of its children.
+ */
+ virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+
+ void CopyTo( TiXmlElement* target ) const;
+ void ClearThis(); // like clear, but initializes 'this' object as well
+
+ // Used to be public [internal use]
+ #ifdef TIXML_USE_STL
+ virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+ #endif
+ /* [internal use]
+ Reads the "value" of the element -- another element, or text.
+ This should terminate with the current end tag.
+ */
+ const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding );
+
+private:
+
+ TiXmlAttributeSet attributeSet;
+};
+
+
+/** An XML comment.
+*/
+class TiXmlComment : public TiXmlNode
+{
+public:
+ /// Constructs an empty comment.
+ TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {}
+ /// Construct a comment from text.
+ TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) {
+ SetValue( _value );
+ }
+ TiXmlComment( const TiXmlComment& );
+ void operator=( const TiXmlComment& base );
+
+ virtual ~TiXmlComment() {}
+
+ /// Returns a copy of this Comment.
+ virtual TiXmlNode* Clone() const;
+ // Write this Comment to a FILE stream.
+ virtual void Print( FILE* cfile, int depth ) const;
+
+ /* Attribtue parsing starts: at the ! of the !--
+ returns: next char past '>'
+ */
+ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+ virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+ virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+ /** Walk the XML tree visiting this node and all of its children.
+ */
+ virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+ void CopyTo( TiXmlComment* target ) const;
+
+ // used to be public
+ #ifdef TIXML_USE_STL
+ virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+ #endif
+// virtual void StreamOut( TIXML_OSTREAM * out ) const;
+
+private:
+
+};
+
+
+/** XML text. A text node can have 2 ways to output the next. "normal" output
+ and CDATA. It will default to the mode it was parsed from the XML file and
+ you generally want to leave it alone, but you can change the output mode with
+ SetCDATA() and query it with CDATA().
+*/
+class TiXmlText : public TiXmlNode
+{
+ friend class TiXmlElement;
+public:
+ /** Constructor for text element. By default, it is treated as
+ normal, encoded text. If you want it be output as a CDATA text
+ element, set the parameter _cdata to 'true'
+ */
+ TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT)
+ {
+ SetValue( initValue );
+ cdata = false;
+ }
+ virtual ~TiXmlText() {}
+
+ #ifdef TIXML_USE_STL
+ /// Constructor.
+ TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT)
+ {
+ SetValue( initValue );
+ cdata = false;
+ }
+ #endif
+
+ TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); }
+ void operator=( const TiXmlText& base ) { base.CopyTo( this ); }
+
+ // Write this text object to a FILE stream.
+ virtual void Print( FILE* cfile, int depth ) const;
+
+ /// Queries whether this represents text using a CDATA section.
+ bool CDATA() const { return cdata; }
+ /// Turns on or off a CDATA representation of text.
+ void SetCDATA( bool _cdata ) { cdata = _cdata; }
+
+ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+ virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+ virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+ /** Walk the XML tree visiting this node and all of its children.
+ */
+ virtual bool Accept( TiXmlVisitor* content ) const;
+
+protected :
+ /// [internal use] Creates a new Element and returns it.
+ virtual TiXmlNode* Clone() const;
+ void CopyTo( TiXmlText* target ) const;
+
+ bool Blank() const; // returns true if all white space and new lines
+ // [internal use]
+ #ifdef TIXML_USE_STL
+ virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+ #endif
+
+private:
+ bool cdata; // true if this should be input and output as a CDATA style text element
+};
+
+
+/** In correct XML the declaration is the first entry in the file.
+ @verbatim
+ <?xml version="1.0" standalone="yes"?>
+ @endverbatim
+
+ TinyXml will happily read or write files without a declaration,
+ however. There are 3 possible attributes to the declaration:
+ version, encoding, and standalone.
+
+ Note: In this version of the code, the attributes are
+ handled as special cases, not generic attributes, simply
+ because there can only be at most 3 and they are always the same.
+*/
+class TiXmlDeclaration : public TiXmlNode
+{
+public:
+ /// Construct an empty declaration.
+ TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {}
+
+#ifdef TIXML_USE_STL
+ /// Constructor.
+ TiXmlDeclaration( const std::string& _version,
+ const std::string& _encoding,
+ const std::string& _standalone );
+#endif
+
+ /// Construct.
+ TiXmlDeclaration( const char* _version,
+ const char* _encoding,
+ const char* _standalone );
+
+ TiXmlDeclaration( const TiXmlDeclaration& copy );
+ void operator=( const TiXmlDeclaration& copy );
+
+ virtual ~TiXmlDeclaration() {}
+
+ /// Version. Will return an empty string if none was found.
+ const char *Version() const { return version.c_str (); }
+ /// Encoding. Will return an empty string if none was found.
+ const char *Encoding() const { return encoding.c_str (); }
+ /// Is this a standalone document?
+ const char *Standalone() const { return standalone.c_str (); }
+
+ /// Creates a copy of this Declaration and returns it.
+ virtual TiXmlNode* Clone() const;
+ // Print this declaration to a FILE stream.
+ virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;
+ virtual void Print( FILE* cfile, int depth ) const {
+ Print( cfile, depth, 0 );
+ }
+
+ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+ virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+ virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+ /** Walk the XML tree visiting this node and all of its children.
+ */
+ virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+ void CopyTo( TiXmlDeclaration* target ) const;
+ // used to be public
+ #ifdef TIXML_USE_STL
+ virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+ #endif
+
+private:
+
+ TIXML_STRING version;
+ TIXML_STRING encoding;
+ TIXML_STRING standalone;
+};
+
+
+/** Any tag that tinyXml doesn't recognize is saved as an
+ unknown. It is a tag of text, but should not be modified.
+ It will be written back to the XML, unchanged, when the file
+ is saved.
+
+ DTD tags get thrown into TiXmlUnknowns.
+*/
+class TiXmlUnknown : public TiXmlNode
+{
+public:
+ TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {}
+ virtual ~TiXmlUnknown() {}
+
+ TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); }
+ void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); }
+
+ /// Creates a copy of this Unknown and returns it.
+ virtual TiXmlNode* Clone() const;
+ // Print this Unknown to a FILE stream.
+ virtual void Print( FILE* cfile, int depth ) const;
+
+ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+ virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+ virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+ /** Walk the XML tree visiting this node and all of its children.
+ */
+ virtual bool Accept( TiXmlVisitor* content ) const;
+
+protected:
+ void CopyTo( TiXmlUnknown* target ) const;
+
+ #ifdef TIXML_USE_STL
+ virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+ #endif
+
+private:
+
+};
+
+
+/** Always the top level node. A document binds together all the
+ XML pieces. It can be saved, loaded, and printed to the screen.
+ The 'value' of a document node is the xml file name.
+*/
+class TiXmlDocument : public TiXmlNode
+{
+public:
+ /// Create an empty document, that has no name.
+ TiXmlDocument();
+ /// Create a document with a name. The name of the document is also the filename of the xml.
+ TiXmlDocument( const char * documentName );
+
+ #ifdef TIXML_USE_STL
+ /// Constructor.
+ TiXmlDocument( const std::string& documentName );
+ #endif
+
+ TiXmlDocument( const TiXmlDocument& copy );
+ void operator=( const TiXmlDocument& copy );
+
+ virtual ~TiXmlDocument();
+
+ /** Load a file using the current document value.
+ Returns true if successful. Will delete any existing
+ document data before loading.
+ */
+ bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+ /// Save a file using the current document value. Returns true if successful.
+ bool SaveFile() const;
+ /// Load a file using the given filename. Returns true if successful.
+ bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+ /// Save a file using the given filename. Returns true if successful.
+ bool SaveFile( const char * filename ) const;
+ /** Load a file using the given FILE*. Returns true if successful. Note that this method
+ doesn't stream - the entire object pointed at by the FILE*
+ will be interpreted as an XML file. TinyXML doesn't stream in XML from the current
+ file location. Streaming may be added in the future.
+ */
+ bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+ /// Save a file using the given FILE*. Returns true if successful.
+ bool SaveFile( FILE* ) const;
+
+ #ifdef TIXML_USE_STL
+ bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version.
+ {
+// StringToBuffer f( filename );
+// return ( f.buffer && LoadFile( f.buffer, encoding ));
+ return LoadFile( filename.c_str(), encoding );
+ }
+ bool SaveFile( const std::string& filename ) const ///< STL std::string version.
+ {
+// StringToBuffer f( filename );
+// return ( f.buffer && SaveFile( f.buffer ));
+ return SaveFile( filename.c_str() );
+ }
+ #endif
+
+ /** Parse the given null terminated block of xml data. Passing in an encoding to this
+ method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml
+ to use that encoding, regardless of what TinyXml might otherwise try to detect.
+ */
+ virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+
+ /** Get the root element -- the only top level element -- of the document.
+ In well formed XML, there should only be one. TinyXml is tolerant of
+ multiple elements at the document level.
+ */
+ const TiXmlElement* RootElement() const { return FirstChildElement(); }
+ TiXmlElement* RootElement() { return FirstChildElement(); }
+
+ /** If an error occurs, Error will be set to true. Also,
+ - The ErrorId() will contain the integer identifier of the error (not generally useful)
+ - The ErrorDesc() method will return the name of the error. (very useful)
+ - The ErrorRow() and ErrorCol() will return the location of the error (if known)
+ */
+ bool Error() const { return error; }
+
+ /// Contains a textual (english) description of the error if one occurs.
+ const char * ErrorDesc() const { return errorDesc.c_str (); }
+
+ /** Generally, you probably want the error string ( ErrorDesc() ). But if you
+ prefer the ErrorId, this function will fetch it.
+ */
+ int ErrorId() const { return errorId; }
+
+ /** Returns the location (if known) of the error. The first column is column 1,
+ and the first row is row 1. A value of 0 means the row and column wasn't applicable
+ (memory errors, for example, have no row/column) or the parser lost the error. (An
+ error in the error reporting, in that case.)
+
+ @sa SetTabSize, Row, Column
+ */
+ int ErrorRow() const { return errorLocation.row+1; }
+ int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow()
+
+ /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol())
+ to report the correct values for row and column. It does not change the output
+ or input in any way.
+
+ By calling this method, with a tab size
+ greater than 0, the row and column of each node and attribute is stored
+ when the file is loaded. Very useful for tracking the DOM back in to
+ the source file.
+
+ The tab size is required for calculating the location of nodes. If not
+ set, the default of 4 is used. The tabsize is set per document. Setting
+ the tabsize to 0 disables row/column tracking.
+
+ Note that row and column tracking is not supported when using operator>>.
+
+ The tab size needs to be enabled before the parse or load. Correct usage:
+ @verbatim
+ TiXmlDocument doc;
+ doc.SetTabSize( 8 );
+ doc.Load( "myfile.xml" );
+ @endverbatim
+
+ @sa Row, Column
+ */
+ void SetTabSize( int _tabsize ) { tabsize = _tabsize; }
+
+ int TabSize() const { return tabsize; }
+
+ /** If you have handled the error, it can be reset with this call. The error
+ state is automatically cleared if you Parse a new XML block.
+ */
+ void ClearError() { error = false;
+ errorId = 0;
+ errorDesc = "";
+ errorLocation.row = errorLocation.col = 0;
+ //errorLocation.last = 0;
+ }
+
+ /** Write the document to standard out using formatted printing ("pretty print"). */
+ void Print() const { Print( stdout, 0 ); }
+
+ /* Write the document to a string using formatted printing ("pretty print"). This
+ will allocate a character array (new char[]) and return it as a pointer. The
+ calling code pust call delete[] on the return char* to avoid a memory leak.
+ */
+ //char* PrintToMemory() const;
+
+ /// Print this Document to a FILE stream.
+ virtual void Print( FILE* cfile, int depth = 0 ) const;
+ // [internal use]
+ void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding );
+
+ virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+ virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+ /** Walk the XML tree visiting this node and all of its children.
+ */
+ virtual bool Accept( TiXmlVisitor* content ) const;
+
+#ifdef HAS_ICONV
+ void SetConvertToUtf8(bool convert) { convertToUtf8 = convert; }
+ bool convertToUtf8;
+ iconv_t iconvContext;
+#endif
+
+protected :
+ // [internal use]
+ virtual TiXmlNode* Clone() const;
+ #ifdef TIXML_USE_STL
+ virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+ #endif
+
+private:
+ void CopyTo( TiXmlDocument* target ) const;
+
+ bool error;
+ int errorId;
+ TIXML_STRING errorDesc;
+ int tabsize;
+ TiXmlCursor errorLocation;
+ bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write.
+};
+
+
+/**
+ A TiXmlHandle is a class that wraps a node pointer with null checks; this is
+ an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml
+ DOM structure. It is a separate utility class.
+
+ Take an example:
+ @verbatim
+ <Document>
+ <Element attributeA = "valueA">
+ <Child attributeB = "value1" />
+ <Child attributeB = "value2" />
+ </Element>
+ <Document>
+ @endverbatim
+
+ Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
+ easy to write a *lot* of code that looks like:
+
+ @verbatim
+ TiXmlElement* root = document.FirstChildElement( "Document" );
+ if ( root )
+ {
+ TiXmlElement* element = root->FirstChildElement( "Element" );
+ if ( element )
+ {
+ TiXmlElement* child = element->FirstChildElement( "Child" );
+ if ( child )
+ {
+ TiXmlElement* child2 = child->NextSiblingElement( "Child" );
+ if ( child2 )
+ {
+ // Finally do something useful.
+ @endverbatim
+
+ And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity
+ of such code. A TiXmlHandle checks for null pointers so it is perfectly safe
+ and correct to use:
+
+ @verbatim
+ TiXmlHandle docHandle( &document );
+ TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement();
+ if ( child2 )
+ {
+ // do something useful
+ @endverbatim
+
+ Which is MUCH more concise and useful.
+
+ It is also safe to copy handles - internally they are nothing more than node pointers.
+ @verbatim
+ TiXmlHandle handleCopy = handle;
+ @endverbatim
+
+ What they should not be used for is iteration:
+
+ @verbatim
+ int i=0;
+ while ( true )
+ {
+ TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement();
+ if ( !child )
+ break;
+ // do something
+ ++i;
+ }
+ @endverbatim
+
+ It seems reasonable, but it is in fact two embedded while loops. The Child method is
+ a linear walk to find the element, so this code would iterate much more than it needs
+ to. Instead, prefer:
+
+ @verbatim
+ TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement();
+
+ for( child; child; child=child->NextSiblingElement() )
+ {
+ // do something
+ }
+ @endverbatim
+*/
+class TiXmlHandle
+{
+public:
+ /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
+ TiXmlHandle( TiXmlNode* _node ) { this->node = _node; }
+ /// Copy constructor
+ TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; }
+ TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; }
+
+ /// Return a handle to the first child node.
+ TiXmlHandle FirstChild() const;
+ /// Return a handle to the first child node with the given name.
+ TiXmlHandle FirstChild( const char * value ) const;
+ /// Return a handle to the first child element.
+ TiXmlHandle FirstChildElement() const;
+ /// Return a handle to the first child element with the given name.
+ TiXmlHandle FirstChildElement( const char * value ) const;
+
+ /** Return a handle to the "index" child with the given name.
+ The first child is 0, the second 1, etc.
+ */
+ TiXmlHandle Child( const char* value, int index ) const;
+ /** Return a handle to the "index" child.
+ The first child is 0, the second 1, etc.
+ */
+ TiXmlHandle Child( int index ) const;
+ /** Return a handle to the "index" child element with the given name.
+ The first child element is 0, the second 1, etc. Note that only TiXmlElements
+ are indexed: other types are not counted.
+ */
+ TiXmlHandle ChildElement( const char* value, int index ) const;
+ /** Return a handle to the "index" child element.
+ The first child element is 0, the second 1, etc. Note that only TiXmlElements
+ are indexed: other types are not counted.
+ */
+ TiXmlHandle ChildElement( int index ) const;
+
+ #ifdef TIXML_USE_STL
+ TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); }
+ TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); }
+
+ TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); }
+ TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); }
+ #endif
+
+ /** Return the handle as a TiXmlNode. This may return null.
+ */
+ TiXmlNode* ToNode() const { return node; }
+ /** Return the handle as a TiXmlElement. This may return null.
+ */
+ TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
+ /** Return the handle as a TiXmlText. This may return null.
+ */
+ TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
+ /** Return the handle as a TiXmlUnknown. This may return null.
+ */
+ TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
+
+ /** @deprecated use ToNode.
+ Return the handle as a TiXmlNode. This may return null.
+ */
+ TiXmlNode* Node() const { return ToNode(); }
+ /** @deprecated use ToElement.
+ Return the handle as a TiXmlElement. This may return null.
+ */
+ TiXmlElement* Element() const { return ToElement(); }
+ /** @deprecated use ToText()
+ Return the handle as a TiXmlText. This may return null.
+ */
+ TiXmlText* Text() const { return ToText(); }
+ /** @deprecated use ToUnknown()
+ Return the handle as a TiXmlUnknown. This may return null.
+ */
+ TiXmlUnknown* Unknown() const { return ToUnknown(); }
+
+private:
+ TiXmlNode* node;
+};
+
+
+/** Print to memory functionality. The TiXmlPrinter is useful when you need to:
+
+ -# Print to memory (especially in non-STL mode)
+ -# Control formatting (line endings, etc.)
+
+ When constructed, the TiXmlPrinter is in its default "pretty printing" mode.
+ Before calling Accept() you can call methods to control the printing
+ of the XML document. After TiXmlNode::Accept() is called, the printed document can
+ be accessed via the CStr(), Str(), and Size() methods.
+
+ TiXmlPrinter uses the Visitor API.
+ @verbatim
+ TiXmlPrinter printer;
+ printer.SetIndent( "\t" );
+
+ doc.Accept( &printer );
+ fprintf( stdout, "%s", printer.CStr() );
+ @endverbatim
+*/
+class TiXmlPrinter : public TiXmlVisitor
+{
+public:
+ TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ),
+ buffer(), indent( " " ), lineBreak( "\n" ) {}
+
+ virtual bool VisitEnter( const TiXmlDocument& doc );
+ virtual bool VisitExit( const TiXmlDocument& doc );
+
+ virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute );
+ virtual bool VisitExit( const TiXmlElement& element );
+
+ virtual bool Visit( const TiXmlDeclaration& declaration );
+ virtual bool Visit( const TiXmlText& text );
+ virtual bool Visit( const TiXmlComment& comment );
+ virtual bool Visit( const TiXmlUnknown& unknown );
+
+ /** Set the indent characters for printing. By default 4 spaces
+ but tab (\t) is also useful, or null/empty string for no indentation.
+ */
+ void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; }
+ /// Query the indention string.
+ const char* Indent() { return indent.c_str(); }
+ /** Set the line breaking string. By default set to newline (\n).
+ Some operating systems prefer other characters, or can be
+ set to the null/empty string for no indenation.
+ */
+ void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; }
+ /// Query the current line breaking string.
+ const char* LineBreak() { return lineBreak.c_str(); }
+
+ /** Switch over to "stream printing" which is the most dense formatting without
+ linebreaks. Common when the XML is needed for network transmission.
+ */
+ void SetStreamPrinting() { indent = "";
+ lineBreak = "";
+ }
+ /// Return the result.
+ const char* CStr() { return buffer.c_str(); }
+ /// Return the length of the result string.
+ size_t Size() { return buffer.size(); }
+
+ #ifdef TIXML_USE_STL
+ /// Return the result.
+ const std::string& Str() { return buffer; }
+ #endif
+
+private:
+ void DoIndent() {
+ for( int i=0; i<depth; ++i )
+ buffer += indent;
+ }
+ void DoLineBreak() {
+ buffer += lineBreak;
+ }
+
+ int depth;
+ bool simpleTextPrint;
+ TIXML_STRING buffer;
+ TIXML_STRING indent;
+ TIXML_STRING lineBreak;
+};
+
+
+#ifdef _MSC_VER
+#pragma warning( pop )
+#endif
+
+#endif
+
diff --git a/guilib/tinyXML/tinyxmlerror.cpp b/guilib/tinyXML/tinyxmlerror.cpp
new file mode 100644
index 0000000000..d24f63b2e5
--- /dev/null
+++ b/guilib/tinyXML/tinyxmlerror.cpp
@@ -0,0 +1,53 @@
+/*
+www.sourceforge.net/projects/tinyxml
+Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+#include "tinyxml.h"
+
+// The goal of the seperate error file is to make the first
+// step towards localization. tinyxml (currently) only supports
+// english error messages, but the could now be translated.
+//
+// It also cleans up the code a bit.
+//
+
+const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] =
+{
+ "No error",
+ "Error",
+ "Failed to open file",
+ "Memory allocation failed.",
+ "Error parsing Element.",
+ "Failed to read Element name",
+ "Error reading Element value.",
+ "Error reading Attributes.",
+ "Error: empty tag.",
+ "Error reading end tag.",
+ "Error parsing Unknown.",
+ "Error parsing Comment.",
+ "Error parsing Declaration.",
+ "Error document empty.",
+ "Error null (0) or unexpected EOF found in input stream.",
+ "Error parsing CDATA.",
+ "Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.",
+};
diff --git a/guilib/tinyXML/tinyxmlparser.cpp b/guilib/tinyXML/tinyxmlparser.cpp
new file mode 100644
index 0000000000..712eb10654
--- /dev/null
+++ b/guilib/tinyXML/tinyxmlparser.cpp
@@ -0,0 +1,1683 @@
+/*
+www.sourceforge.net/projects/tinyxml
+Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+#include <ctype.h>
+#include <stddef.h>
+
+#include "tinyxml.h"
+#include "CharsetConverter.h"
+
+//#define DEBUG_PARSER
+#if defined( DEBUG_PARSER )
+# if defined( DEBUG ) && defined( _MSC_VER )
+# include <windows.h>
+# define TIXML_LOG OutputDebugString
+# else
+# define TIXML_LOG printf
+# endif
+#endif
+
+// Note tha "PutString" hardcodes the same list. This
+// is less flexible than it appears. Changing the entries
+// or order will break putstring.
+TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] =
+{
+ { "&amp;", 5, '&' },
+ { "&lt;", 4, '<' },
+ { "&gt;", 4, '>' },
+ { "&quot;", 6, '\"' },
+ { "&apos;", 6, '\'' }
+};
+
+// Bunch of unicode info at:
+// http://www.unicode.org/faq/utf_bom.html
+// Including the basic of this table, which determines the #bytes in the
+// sequence from the lead byte. 1 placed for invalid sequences --
+// although the result will be junk, pass it through as much as possible.
+// Beware of the non-characters in UTF-8:
+// ef bb bf (Microsoft "lead bytes")
+// ef bf be
+// ef bf bf
+
+const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
+const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
+const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
+
+const int TiXmlBase::utf8ByteTable[256] =
+{
+ // 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0
+ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte
+ 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid
+};
+
+
+void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
+{
+ const unsigned long BYTE_MASK = 0xBF;
+ const unsigned long BYTE_MARK = 0x80;
+ const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+ if (input < 0x80)
+ *length = 1;
+ else if ( input < 0x800 )
+ *length = 2;
+ else if ( input < 0x10000 )
+ *length = 3;
+ else if ( input < 0x200000 )
+ *length = 4;
+ else
+ { *length = 0; return; } // This code won't covert this correctly anyway.
+
+ output += *length;
+
+ // Scary scary fall throughs.
+ switch (*length)
+ {
+ case 4:
+ --output;
+ *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+ input >>= 6;
+ case 3:
+ --output;
+ *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+ input >>= 6;
+ case 2:
+ --output;
+ *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+ input >>= 6;
+ case 1:
+ --output;
+ *output = (char)(input | FIRST_BYTE_MARK[*length]);
+ }
+}
+
+
+/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
+{
+ // This will only work for low-ascii, everything else is assumed to be a valid
+ // letter. I'm not sure this is the best approach, but it is quite tricky trying
+ // to figure out alhabetical vs. not across encoding. So take a very
+ // conservative approach.
+
+// if ( encoding == TIXML_ENCODING_UTF8 )
+// {
+ if ( anyByte < 127 )
+ return isalpha( anyByte );
+ else
+ return 1; // What else to do? The unicode set is huge...get the english ones right.
+// }
+// else
+// {
+// return isalpha( anyByte );
+// }
+}
+
+
+/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
+{
+ // This will only work for low-ascii, everything else is assumed to be a valid
+ // letter. I'm not sure this is the best approach, but it is quite tricky trying
+ // to figure out alhabetical vs. not across encoding. So take a very
+ // conservative approach.
+
+// if ( encoding == TIXML_ENCODING_UTF8 )
+// {
+ if ( anyByte < 127 )
+ return isalnum( anyByte );
+ else
+ return 1; // What else to do? The unicode set is huge...get the english ones right.
+// }
+// else
+// {
+// return isalnum( anyByte );
+// }
+}
+
+
+class TiXmlParsingData
+{
+ friend class TiXmlDocument;
+ public:
+ void Stamp( const char* now, TiXmlEncoding encoding );
+
+ const TiXmlCursor& Cursor() { return cursor; }
+
+ private:
+ // Only used by the document!
+ TiXmlParsingData( const char* start, int _tabsize, int row, int col )
+ {
+ assert( start );
+ stamp = start;
+ tabsize = _tabsize;
+ cursor.row = row;
+ cursor.col = col;
+ }
+
+ TiXmlCursor cursor;
+ const char* stamp;
+ int tabsize;
+};
+
+
+void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding )
+{
+ assert( now );
+
+ // Do nothing if the tabsize is 0.
+ if ( tabsize < 1 )
+ {
+ return;
+ }
+
+ // Get the current row, column.
+ int row = cursor.row;
+ int col = cursor.col;
+ const char* p = stamp;
+ assert( p );
+
+ while ( p < now )
+ {
+ // Treat p as unsigned, so we have a happy compiler.
+ const unsigned char* pU = (const unsigned char*)p;
+
+ // Code contributed by Fletcher Dunn: (modified by lee)
+ switch (*pU) {
+ case 0:
+ // We *should* never get here, but in case we do, don't
+ // advance past the terminating null character, ever
+ return;
+
+ case '\r':
+ // bump down to the next line
+ ++row;
+ col = 0;
+ // Eat the character
+ ++p;
+
+ // Check for \r\n sequence, and treat this as a single character
+ if (*p == '\n') {
+ ++p;
+ }
+ break;
+
+ case '\n':
+ // bump down to the next line
+ ++row;
+ col = 0;
+
+ // Eat the character
+ ++p;
+
+ // Check for \n\r sequence, and treat this as a single
+ // character. (Yes, this bizarre thing does occur still
+ // on some arcane platforms...)
+ if (*p == '\r') {
+ ++p;
+ }
+ break;
+
+ case '\t':
+ // Eat the character
+ ++p;
+
+ // Skip to next tab stop
+ col = (col / tabsize + 1) * tabsize;
+ break;
+
+ case TIXML_UTF_LEAD_0:
+ if ( encoding == TIXML_ENCODING_UTF8 )
+ {
+ if ( *(p+1) && *(p+2) )
+ {
+ // In these cases, don't advance the column. These are
+ // 0-width spaces.
+ if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 )
+ p += 3;
+ else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU )
+ p += 3;
+ else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU )
+ p += 3;
+ else
+ { p +=3; ++col; } // A normal character.
+ }
+ }
+ else
+ {
+ ++p;
+ ++col;
+ }
+ break;
+
+ default:
+ if ( encoding == TIXML_ENCODING_UTF8 )
+ {
+ // Eat the 1 to 4 byte utf8 character.
+ int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)];
+ if ( step == 0 )
+ step = 1; // Error case from bad encoding, but handle gracefully.
+ p += step;
+
+ // Just advance one column, of course.
+ ++col;
+ }
+ else
+ {
+ ++p;
+ ++col;
+ }
+ break;
+ }
+ }
+ cursor.row = row;
+ cursor.col = col;
+ assert( cursor.row >= -1 );
+ assert( cursor.col >= -1 );
+ stamp = p;
+ assert( stamp );
+}
+
+
+const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding )
+{
+ if ( !p || !*p )
+ {
+ return 0;
+ }
+ if ( encoding == TIXML_ENCODING_UTF8 )
+ {
+ while ( *p )
+ {
+ const unsigned char* pU = (const unsigned char*)p;
+
+ // Skip the stupid Microsoft UTF-8 Byte order marks
+ if ( *(pU+0)==TIXML_UTF_LEAD_0
+ && *(pU+1)==TIXML_UTF_LEAD_1
+ && *(pU+2)==TIXML_UTF_LEAD_2 )
+ {
+ p += 3;
+ continue;
+ }
+ else if(*(pU+0)==TIXML_UTF_LEAD_0
+ && *(pU+1)==0xbfU
+ && *(pU+2)==0xbeU )
+ {
+ p += 3;
+ continue;
+ }
+ else if(*(pU+0)==TIXML_UTF_LEAD_0
+ && *(pU+1)==0xbfU
+ && *(pU+2)==0xbfU )
+ {
+ p += 3;
+ continue;
+ }
+
+ if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space.
+ ++p;
+ else
+ break;
+ }
+ }
+ else
+ {
+ while ( *p && (IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ))
+ ++p;
+ }
+
+ return p;
+}
+
+#ifdef TIXML_USE_STL
+/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag )
+{
+ for( ;; )
+ {
+ if ( !in->good() ) return false;
+
+ int c = in->peek();
+ // At this scope, we can't get to a document. So fail silently.
+ if ( !IsWhiteSpace( c ) || c <= 0 )
+ return true;
+
+ *tag += (char) in->get();
+ }
+}
+
+/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag )
+{
+ //assert( character > 0 && character < 128 ); // else it won't work in utf-8
+ while ( in->good() )
+ {
+ int c = in->peek();
+ if ( c == character )
+ return true;
+ if ( c <= 0 ) // Silent failure: can't get document at this scope
+ return false;
+
+ in->get();
+ *tag += (char) c;
+ }
+ return false;
+}
+#endif
+
+// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The
+// "assign" optimization removes over 10% of the execution time.
+//
+const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding )
+{
+ // Oddly, not supported on some comilers,
+ //name->clear();
+ // So use this:
+ *name = "";
+ assert( p );
+
+ // Names start with letters or underscores.
+ // Of course, in unicode, tinyxml has no idea what a letter *is*. The
+ // algorithm is generous.
+ //
+ // After that, they can be letters, underscores, numbers,
+ // hyphens, or colons. (Colons are valid ony for namespaces,
+ // but tinyxml can't tell namespaces from names.)
+ if ( p && *p
+ && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) )
+ {
+ const char* start = p;
+ while( p && *p
+ && ( IsAlphaNum( (unsigned char ) *p, encoding )
+ || *p == '_'
+ || *p == '-'
+ || *p == '.'
+ || *p == ':' ) )
+ {
+ //(*name) += *p; // expensive
+ ++p;
+ }
+ if ( p-start > 0 ) {
+ name->assign( start, p-start );
+ }
+ return p;
+ }
+ return 0;
+}
+
+const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding )
+{
+ // Presume an entity, and pull it out.
+ TIXML_STRING ent;
+ int i;
+
+ if ( *(p+1) && *(p+1) == '#' && *(p+2) )
+ {
+ unsigned long ucs = 0;
+ ptrdiff_t delta = 0;
+ unsigned mult = 1;
+
+ if ( *(p+2) == 'x' )
+ {
+ // Hexadecimal.
+ if ( !*(p+3) ) return 0;
+
+ const char* q = p+3;
+ q = strchr( q, ';' );
+
+ if ( !q || !*q ) return 0;
+
+ delta = q-p;
+ --q;
+
+ while ( *q != 'x' )
+ {
+ if ( *q >= '0' && *q <= '9' )
+ ucs += mult * (*q - '0');
+ else if ( *q >= 'a' && *q <= 'f' )
+ ucs += mult * (*q - 'a' + 10);
+ else if ( *q >= 'A' && *q <= 'F' )
+ ucs += mult * (*q - 'A' + 10 );
+ else
+ return 0;
+ mult *= 16;
+ --q;
+ }
+ }
+ else
+ {
+ // Decimal.
+ if ( !*(p+2) ) return 0;
+
+ const char* q = p+2;
+ q = strchr( q, ';' );
+
+ if ( !q || !*q ) return 0;
+
+ delta = q-p;
+ --q;
+
+ while ( *q != '#' )
+ {
+ if ( *q >= '0' && *q <= '9' )
+ ucs += mult * (*q - '0');
+ else
+ return 0;
+ mult *= 10;
+ --q;
+ }
+ }
+ if ( encoding == TIXML_ENCODING_UTF8 )
+ {
+ // convert the UCS to UTF-8
+ ConvertUTF32ToUTF8( ucs, value, length );
+ }
+ else
+ {
+ *value = (char)ucs;
+ *length = 1;
+ }
+ return p + delta + 1;
+ }
+
+ // Now try to match it.
+ for( i=0; i<NUM_ENTITY; ++i )
+ {
+ if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
+ {
+ assert( strlen( entity[i].str ) == entity[i].strLength );
+ *value = entity[i].chr;
+ *length = 1;
+ return ( p + entity[i].strLength );
+ }
+ }
+
+ // So it wasn't an entity, its unrecognized, or something like that.
+ *value = *p; // Don't put back the last one, since we return it!
+ *length = 1; // Leave unrecognized entities - this doesn't really work.
+ // Just writes strange XML.
+ return p+1;
+}
+
+
+bool TiXmlBase::StringEqual( const char* p,
+ const char* tag,
+ bool ignoreCase,
+ TiXmlEncoding encoding )
+{
+ assert( p );
+ assert( tag );
+ if ( !p || !*p )
+ {
+ assert( 0 );
+ return false;
+ }
+
+ const char* q = p;
+
+ if ( ignoreCase )
+ {
+ while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) )
+ {
+ ++q;
+ ++tag;
+ }
+
+ if ( *tag == 0 )
+ return true;
+ }
+ else
+ {
+ while ( *q && *tag && *q == *tag )
+ {
+ ++q;
+ ++tag;
+ }
+
+ if ( *tag == 0 ) // Have we found the end of the tag, and everything equal?
+ return true;
+ }
+ return false;
+}
+
+const char* TiXmlBase::ReadText( const char* p,
+ TIXML_STRING * text,
+ bool trimWhiteSpace,
+ const char* endTag,
+ bool caseInsensitive,
+ TiXmlEncoding encoding )
+{
+ *text = "";
+ if ( !trimWhiteSpace // certain tags always keep whitespace
+ || !condenseWhiteSpace ) // if true, whitespace is always kept
+ {
+ // Keep all the white space.
+ while ( p && *p
+ && !StringEqual( p, endTag, caseInsensitive, encoding )
+ )
+ {
+ int len;
+ char cArr[4] = { 0, 0, 0, 0 };
+ p = GetChar( p, cArr, &len, encoding );
+ text->append( cArr, len );
+ }
+ }
+ else
+ {
+ bool whitespace = false;
+
+ // Remove leading white space:
+ p = SkipWhiteSpace( p, encoding );
+ while ( p && *p
+ && !StringEqual( p, endTag, caseInsensitive, encoding ) )
+ {
+ if ( *p == '\r' || *p == '\n' )
+ {
+ whitespace = true;
+ ++p;
+ }
+ else if ( IsWhiteSpace( *p ) )
+ {
+ whitespace = true;
+ ++p;
+ }
+ else
+ {
+ // If we've found whitespace, add it before the
+ // new character. Any whitespace just becomes a space.
+ if ( whitespace )
+ {
+ (*text) += ' ';
+ whitespace = false;
+ }
+ int len;
+ char cArr[4] = { 0, 0, 0, 0 };
+ p = GetChar( p, cArr, &len, encoding );
+ if ( len == 1 )
+ (*text) += cArr[0]; // more efficient
+ else
+ text->append( cArr, len );
+ }
+ }
+ }
+ if ( p )
+ p += strlen( endTag );
+ return p;
+}
+
+#ifdef HAS_ICONV
+void TiXmlBase::ConvertToUtf8(TiXmlDocument* document, TIXML_STRING* text)
+{
+ if (!document) return;
+ if (!document->convertToUtf8) return;
+ if (document->iconvContext == (iconv_t) -1) return;
+
+#ifdef TIXML_USE_STL
+
+ size_t olen = (text->size() * 4) + 1;
+ char* output = new char[olen];
+ char* obuf = output;
+ size_t ilen = text->size() + 1;
+ const char* ibuf = (const char*) text->c_str();
+
+ if (iconv_const(document->iconvContext, &ibuf, &ilen, &obuf, &olen) == (size_t) -1)
+ {
+ delete [] output;
+ return;
+ }
+
+ *text = output;
+ delete [] output;
+#endif
+}
+#endif
+
+#ifdef TIXML_USE_STL
+
+void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+ // The basic issue with a document is that we don't know what we're
+ // streaming. Read something presumed to be a tag (and hope), then
+ // identify it, and call the appropriate stream method on the tag.
+ //
+ // This "pre-streaming" will never read the closing ">" so the
+ // sub-tag can orient itself.
+
+ if ( !StreamTo( in, '<', tag ) )
+ {
+ SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+
+ while ( in->good() )
+ {
+ int tagIndex = (int) tag->length();
+ while ( in->good() && in->peek() != '>' )
+ {
+ int c = in->get();
+ if ( c <= 0 )
+ {
+ SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ break;
+ }
+ (*tag) += (char) c;
+ }
+
+ if ( in->good() )
+ {
+ // We now have something we presume to be a node of
+ // some sort. Identify it, and call the node to
+ // continue streaming.
+ TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING );
+
+ if ( node )
+ {
+ node->StreamIn( in, tag );
+ bool isElement = node->ToElement() != 0;
+ delete node;
+ node = 0;
+
+ // If this is the root element, we're done. Parsing will be
+ // done by the >> operator.
+ if ( isElement )
+ {
+ return;
+ }
+ }
+ else
+ {
+ SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+ }
+ }
+ // We should have returned sooner.
+ SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
+}
+
+#endif
+
+const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding )
+{
+ ClearError();
+
+ // Parse away, at the document level. Since a document
+ // contains nothing but other tags, most of what happens
+ // here is skipping white space.
+ if ( !p || !*p )
+ {
+ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return 0;
+ }
+
+ // Note that, for a document, this needs to come
+ // before the while space skip, so that parsing
+ // starts from the pointer we are given.
+ location.Clear();
+ if ( prevData )
+ {
+ location.row = prevData->cursor.row;
+ location.col = prevData->cursor.col;
+ }
+ else
+ {
+ location.row = 0;
+ location.col = 0;
+ }
+ TiXmlParsingData data( p, TabSize(), location.row, location.col );
+ location = data.Cursor();
+
+ if ( encoding == TIXML_ENCODING_UNKNOWN )
+ {
+ // Check for the Microsoft UTF-8 lead bytes.
+ const unsigned char* pU = (const unsigned char*)p;
+ if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0
+ && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1
+ && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 )
+ {
+ encoding = TIXML_ENCODING_UTF8;
+ useMicrosoftBOM = true;
+ }
+ }
+
+ p = SkipWhiteSpace( p, encoding );
+ if ( !p )
+ {
+ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return 0;
+ }
+
+ while ( p && *p )
+ {
+ TiXmlNode* node = Identify( p, encoding );
+ if ( node )
+ {
+ p = node->Parse( p, &data, encoding );
+ LinkEndChild( node );
+ }
+ else
+ {
+ break;
+ }
+
+ // Did we get encoding info?
+ if ( encoding == TIXML_ENCODING_UNKNOWN
+ && node->ToDeclaration() )
+ {
+ TiXmlDeclaration* dec = node->ToDeclaration();
+ const char* enc = dec->Encoding();
+ assert( enc );
+
+ if ( *enc == 0 )
+ encoding = TIXML_ENCODING_UTF8;
+ else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) )
+ encoding = TIXML_ENCODING_UTF8;
+ else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) )
+ encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice
+ else
+ {
+#ifdef HAS_ICONV
+ if (convertToUtf8)
+ {
+ if (iconvContext != (iconv_t) -1)
+ {
+ iconv_close(iconvContext);
+ iconvContext = (iconv_t) -1;
+ }
+
+ iconvContext = iconv_open("UTF8", enc);
+ }
+#endif
+ encoding = TIXML_ENCODING_LEGACY;
+ }
+ }
+
+ p = SkipWhiteSpace( p, encoding );
+ }
+
+ // Was this empty?
+ if ( !firstChild ) {
+ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding );
+ return 0;
+ }
+
+ // All is well.
+ return p;
+}
+
+void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+ // The first error in a chain is more accurate - don't set again!
+ if ( error )
+ return;
+
+ assert( err > 0 && err < TIXML_ERROR_STRING_COUNT );
+ error = true;
+ errorId = err;
+ errorDesc = errorString[ errorId ];
+
+ errorLocation.Clear();
+ if ( pError && data )
+ {
+ data->Stamp( pError, encoding );
+ errorLocation = data->Cursor();
+ }
+}
+
+
+TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding )
+{
+ TiXmlNode* returnNode = 0;
+
+ p = SkipWhiteSpace( p, encoding );
+ if( !p || !*p || *p != '<' )
+ {
+ return 0;
+ }
+
+ TiXmlDocument* doc = GetDocument();
+ p = SkipWhiteSpace( p, encoding );
+
+ if ( !p || !*p )
+ {
+ return 0;
+ }
+
+ // What is this thing?
+ // - Elements start with a letter or underscore, but xml is reserved.
+ // - Comments: <!--
+ // - Decleration: <?xml
+ // - Everthing else is unknown to tinyxml.
+ //
+
+ const char* xmlHeader = { "<?xml" };
+ const char* commentHeader = { "<!--" };
+ const char* dtdHeader = { "<!" };
+ const char* cdataHeader = { "<![CDATA[" };
+
+ if ( StringEqual( p, xmlHeader, true, encoding ) )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Declaration\n" );
+ #endif
+ returnNode = new TiXmlDeclaration();
+ }
+ else if ( StringEqual( p, commentHeader, false, encoding ) )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Comment\n" );
+ #endif
+ returnNode = new TiXmlComment();
+ }
+ else if ( StringEqual( p, cdataHeader, false, encoding ) )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing CDATA\n" );
+ #endif
+ TiXmlText* text = new TiXmlText( "" );
+ text->SetCDATA( true );
+ returnNode = text;
+ }
+ else if ( StringEqual( p, dtdHeader, false, encoding ) )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Unknown(1)\n" );
+ #endif
+ returnNode = new TiXmlUnknown();
+ }
+ else if ( IsAlpha( *(p+1), encoding )
+ || *(p+1) == '_' )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Element\n" );
+ #endif
+ returnNode = new TiXmlElement( "" );
+ }
+ else
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Unknown(2)\n" );
+ #endif
+ returnNode = new TiXmlUnknown();
+ }
+
+ if ( returnNode )
+ {
+ // Set the parent, so it can report errors
+ returnNode->parent = this;
+ }
+ else
+ {
+ if ( doc )
+ doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ }
+ return returnNode;
+}
+
+#ifdef TIXML_USE_STL
+
+void TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag)
+{
+ // We're called with some amount of pre-parsing. That is, some of "this"
+ // element is in "tag". Go ahead and stream to the closing ">"
+ while( in->good() )
+ {
+ int c = in->get();
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+ (*tag) += (char) c ;
+
+ if ( c == '>' )
+ break;
+ }
+
+ if ( tag->length() < 3 ) return;
+
+ // Okay...if we are a "/>" tag, then we're done. We've read a complete tag.
+ // If not, identify and stream.
+
+ if ( tag->at( tag->length() - 1 ) == '>'
+ && tag->at( tag->length() - 2 ) == '/' )
+ {
+ // All good!
+ return;
+ }
+ else if ( tag->at( tag->length() - 1 ) == '>' )
+ {
+ // There is more. Could be:
+ // text
+ // cdata text (which looks like another node)
+ // closing tag
+ // another node.
+ for ( ;; )
+ {
+ StreamWhiteSpace( in, tag );
+
+ // Do we have text?
+ if ( in->good() && in->peek() != '<' )
+ {
+ // Yep, text.
+ TiXmlText text( "" );
+ text.StreamIn( in, tag );
+
+ // What follows text is a closing tag or another node.
+ // Go around again and figure it out.
+ continue;
+ }
+
+ // We now have either a closing tag...or another node.
+ // We should be at a "<", regardless.
+ if ( !in->good() ) return;
+ assert( in->peek() == '<' );
+ int tagIndex = (int) tag->length();
+
+ bool closingTag = false;
+ bool firstCharFound = false;
+
+ for( ;; )
+ {
+ if ( !in->good() )
+ return;
+
+ int c = in->peek();
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+
+ if ( c == '>' )
+ break;
+
+ *tag += (char) c;
+ in->get();
+
+ // Early out if we find the CDATA id.
+ if ( c == '[' && tag->size() >= 9 )
+ {
+ size_t len = tag->size();
+ const char* start = tag->c_str() + len - 9;
+ if ( strcmp( start, "<![CDATA[" ) == 0 ) {
+ assert( !closingTag );
+ break;
+ }
+ }
+
+ if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
+ {
+ firstCharFound = true;
+ if ( c == '/' )
+ closingTag = true;
+ }
+ }
+ // If it was a closing tag, then read in the closing '>' to clean up the input stream.
+ // If it was not, the streaming will be done by the tag.
+ if ( closingTag )
+ {
+ if ( !in->good() )
+ return;
+
+ int c = in->get();
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+ assert( c == '>' );
+ *tag += (char) c;
+
+ // We are done, once we've found our closing tag.
+ return;
+ }
+ else
+ {
+ // If not a closing tag, id it, and stream.
+ const char* tagloc = tag->c_str() + tagIndex;
+ TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING );
+ if ( !node )
+ return;
+ node->StreamIn( in, tag );
+ delete node;
+ node = 0;
+
+ // No return: go around from the beginning: text, closing tag, or node.
+ }
+ }
+ }
+}
+#endif
+
+const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+ p = SkipWhiteSpace( p, encoding );
+ TiXmlDocument* document = GetDocument();
+
+ if ( !p || !*p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding );
+ return 0;
+ }
+
+ if ( data )
+ {
+ data->Stamp( p, encoding );
+ location = data->Cursor();
+ }
+
+ if ( *p != '<' )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );
+ return 0;
+ }
+
+ p = SkipWhiteSpace( p+1, encoding );
+
+ // Read the name.
+ const char* pErr = p;
+
+ p = ReadName( p, &value, encoding );
+ if ( !p || !*p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding );
+ return 0;
+ }
+
+ TIXML_STRING endTag ("</");
+ endTag += value;
+ endTag += ">";
+
+ // Check for and read attributes. Also look for an empty
+ // tag or an end tag.
+ while ( p && *p )
+ {
+ pErr = p;
+ p = SkipWhiteSpace( p, encoding );
+ if ( !p || !*p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
+ return 0;
+ }
+ if ( *p == '/' )
+ {
+ ++p;
+ // Empty tag.
+ if ( *p != '>' )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding );
+ return 0;
+ }
+ return (p+1);
+ }
+ else if ( *p == '>' )
+ {
+ // Done with attributes (if there were any.)
+ // Read the value -- which can include other
+ // elements -- read the end tag, and return.
+ ++p;
+ p = ReadValue( p, data, encoding ); // Note this is an Element method, and will set the error if one happens.
+ if ( !p || !*p ) {
+ // We were looking for the end tag, but found nothing.
+ // Fix for [ 1663758 ] Failure to report error on bad XML
+ if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
+ return 0;
+ }
+
+ // We should find the end tag now
+ if ( StringEqual( p, endTag.c_str(), false, encoding ) )
+ {
+ p += endTag.length();
+ return p;
+ }
+ else
+ {
+ if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
+ return 0;
+ }
+ }
+ else
+ {
+ // Try to read an attribute:
+ TiXmlAttribute* attrib = new TiXmlAttribute();
+ if ( !attrib )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding );
+ return 0;
+ }
+
+ attrib->SetDocument( document );
+ pErr = p;
+ p = attrib->Parse( p, data, encoding );
+
+ if ( !p || !*p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
+ delete attrib;
+ return 0;
+ }
+
+ // Handle the strange case of double attributes:
+ #ifdef TIXML_USE_STL
+ TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() );
+ #else
+ TiXmlAttribute* node = attributeSet.Find( attrib->Name() );
+ #endif
+ if ( node )
+ {
+ node->SetValue( attrib->Value() );
+ delete attrib;
+ return 0;
+ }
+
+ attributeSet.Add( attrib );
+ }
+ }
+ return p;
+}
+
+
+const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+ TiXmlDocument* document = GetDocument();
+ // Read in text and elements in any order.
+ const char* pWithWhiteSpace = p;
+ p = SkipWhiteSpace( p, encoding );
+
+ while ( p && *p )
+ {
+ if ( *p != '<' )
+ {
+ // Take what we have, make a text element.
+ TiXmlText* textNode = new TiXmlText( "" );
+
+ if ( !textNode )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding );
+ return 0;
+ }
+
+ if ( TiXmlBase::IsWhiteSpaceCondensed() )
+ {
+ p = textNode->Parse( p, data, encoding );
+ }
+ else
+ {
+ // Special case: we want to keep the white space
+ // so that leading spaces aren't removed.
+ p = textNode->Parse( pWithWhiteSpace, data, encoding );
+ }
+
+ if ( !textNode->Blank() )
+ {
+ LinkEndChild( textNode );
+#ifdef HAS_ICONV
+ ConvertToUtf8(document, &textNode->value);
+#endif
+ }
+ else
+ delete textNode;
+ }
+ else
+ {
+ // We hit a '<'
+ // Have we hit a new element or an end tag? This could also be
+ // a TiXmlText in the "CDATA" style.
+ if ( StringEqual( p, "</", false, encoding ) )
+ {
+ return p;
+ }
+ else
+ {
+ TiXmlNode* node = Identify( p, encoding );
+ if ( node )
+ {
+ p = node->Parse( p, data, encoding );
+ LinkEndChild( node );
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+ pWithWhiteSpace = p;
+ p = SkipWhiteSpace( p, encoding );
+ }
+
+ if ( !p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding );
+ }
+ return p;
+}
+
+
+#ifdef TIXML_USE_STL
+void TiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+ while ( in->good() )
+ {
+ int c = in->get();
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+ (*tag) += (char) c;
+
+ if ( c == '>' )
+ {
+ // All is well.
+ return;
+ }
+ }
+}
+#endif
+
+
+const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+ TiXmlDocument* document = GetDocument();
+ p = SkipWhiteSpace( p, encoding );
+
+ if ( data )
+ {
+ data->Stamp( p, encoding );
+ location = data->Cursor();
+ }
+ if ( !p || !*p || *p != '<' )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding );
+ return 0;
+ }
+ ++p;
+ value = "";
+
+ while ( p && *p && *p != '>' )
+ {
+ value += *p;
+ ++p;
+ }
+
+ if ( !p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding );
+ }
+ if ( *p == '>' )
+ return p+1;
+ return p;
+}
+
+#ifdef TIXML_USE_STL
+void TiXmlComment::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+ while ( in->good() )
+ {
+ int c = in->get();
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+
+ (*tag) += (char) c;
+
+ if ( c == '>'
+ && tag->at( tag->length() - 2 ) == '-'
+ && tag->at( tag->length() - 3 ) == '-' )
+ {
+ // All is well.
+ return;
+ }
+ }
+}
+#endif
+
+
+const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+ TiXmlDocument* document = GetDocument();
+ value = "";
+
+ p = SkipWhiteSpace( p, encoding );
+
+ if ( data )
+ {
+ data->Stamp( p, encoding );
+ location = data->Cursor();
+ }
+ const char* startTag = "<!--";
+ const char* endTag = "-->";
+
+ if ( !StringEqual( p, startTag, false, encoding ) )
+ {
+ document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding );
+ return 0;
+ }
+ p += strlen( startTag );
+
+ // [ 1475201 ] TinyXML parses entities in comments
+ // Oops - ReadText doesn't work, because we don't want to parse the entities.
+ // p = ReadText( p, &value, false, endTag, false, encoding );
+ //
+ // from the XML spec:
+ /*
+ [Definition: Comments may appear anywhere in a document outside other markup; in addition,
+ they may appear within the document type declaration at places allowed by the grammar.
+ They are not part of the document's character data; an XML processor MAY, but need not,
+ make it possible for an application to retrieve the text of comments. For compatibility,
+ the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity
+ references MUST NOT be recognized within comments.
+
+ An example of a comment:
+
+ <!-- declarations for <head> & <body> -->
+ */
+
+ value = "";
+ // Keep all the white space.
+ while ( p && *p && !StringEqual( p, endTag, false, encoding ) )
+ {
+ value.append( p, 1 );
+ ++p;
+ }
+ if ( p )
+ p += strlen( endTag );
+
+ return p;
+}
+
+
+const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+ p = SkipWhiteSpace( p, encoding );
+ if ( !p || !*p ) return 0;
+
+// int tabsize = 4;
+// if ( document )
+// tabsize = document->TabSize();
+
+ if ( data )
+ {
+ data->Stamp( p, encoding );
+ location = data->Cursor();
+ }
+ // Read the name, the '=' and the value.
+ const char* pErr = p;
+ p = ReadName( p, &name, encoding );
+ if ( !p || !*p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
+ return 0;
+ }
+ p = SkipWhiteSpace( p, encoding );
+ if ( !p || !*p || *p != '=' )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
+ return 0;
+ }
+
+ ++p; // skip '='
+ p = SkipWhiteSpace( p, encoding );
+ if ( !p || !*p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
+ return 0;
+ }
+
+ const char* end;
+ const char SINGLE_QUOTE = '\'';
+ const char DOUBLE_QUOTE = '\"';
+
+ if ( *p == SINGLE_QUOTE )
+ {
+ ++p;
+ end = "\'"; // single quote in string
+ p = ReadText( p, &value, false, end, false, encoding );
+ }
+ else if ( *p == DOUBLE_QUOTE )
+ {
+ ++p;
+ end = "\""; // double quote in string
+ p = ReadText( p, &value, false, end, false, encoding );
+ }
+ else
+ {
+ // All attribute values should be in single or double quotes.
+ // But this is such a common error that the parser will try
+ // its best, even without them.
+ value = "";
+ while ( p && *p // existence
+ && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace
+ && *p != '/' && *p != '>' ) // tag end
+ {
+ if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) {
+ // [ 1451649 ] Attribute values with trailing quotes not handled correctly
+ // We did not have an opening quote but seem to have a
+ // closing one. Give up and throw an error.
+ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
+ return 0;
+ }
+ value += *p;
+ ++p;
+ }
+ }
+ return p;
+}
+
+#ifdef TIXML_USE_STL
+void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+ while ( in->good() )
+ {
+ int c = in->peek();
+ if ( !cdata && (c == '<' ) )
+ {
+ return;
+ }
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+
+ (*tag) += (char) c;
+ in->get(); // "commits" the peek made above
+
+ if ( cdata && c == '>' && tag->size() >= 3 ) {
+ size_t len = tag->size();
+ if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) {
+ // terminator of cdata.
+ return;
+ }
+ }
+ }
+}
+#endif
+
+const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+ value = "";
+ TiXmlDocument* document = GetDocument();
+
+ if ( data )
+ {
+ data->Stamp( p, encoding );
+ location = data->Cursor();
+ }
+
+ const char* const startTag = "<![CDATA[";
+ const char* const endTag = "]]>";
+
+ if ( cdata || StringEqual( p, startTag, false, encoding ) )
+ {
+ cdata = true;
+
+ if ( !StringEqual( p, startTag, false, encoding ) )
+ {
+ document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding );
+ return 0;
+ }
+ p += strlen( startTag );
+
+ // Keep all the white space, ignore the encoding, etc.
+ while ( p && *p
+ && !StringEqual( p, endTag, false, encoding )
+ )
+ {
+ value += *p;
+ ++p;
+ }
+
+ TIXML_STRING dummy;
+ p = ReadText( p, &dummy, false, endTag, false, encoding );
+ return p;
+ }
+ else
+ {
+ bool ignoreWhite = true;
+
+ const char* end = "<";
+ p = ReadText( p, &value, ignoreWhite, end, false, encoding );
+ if ( p )
+ return p-1; // don't truncate the '<'
+ return 0;
+ }
+}
+
+#ifdef TIXML_USE_STL
+void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+ while ( in->good() )
+ {
+ int c = in->get();
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+ (*tag) += (char) c;
+
+ if ( c == '>' )
+ {
+ // All is well.
+ return;
+ }
+ }
+}
+#endif
+
+const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding )
+{
+ p = SkipWhiteSpace( p, _encoding );
+ // Find the beginning, find the end, and look for
+ // the stuff in-between.
+ TiXmlDocument* document = GetDocument();
+ if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding );
+ return 0;
+ }
+ if ( data )
+ {
+ data->Stamp( p, _encoding );
+ location = data->Cursor();
+ }
+ p += 5;
+
+ version = "";
+ encoding = "";
+ standalone = "";
+
+ while ( p && *p )
+ {
+ if ( *p == '>' )
+ {
+ ++p;
+ return p;
+ }
+
+ p = SkipWhiteSpace( p, _encoding );
+ if ( StringEqual( p, "version", true, _encoding ) )
+ {
+ TiXmlAttribute attrib;
+ p = attrib.Parse( p, data, _encoding );
+ version = attrib.Value();
+ }
+ else if ( StringEqual( p, "encoding", true, _encoding ) )
+ {
+ TiXmlAttribute attrib;
+ p = attrib.Parse( p, data, _encoding );
+ encoding = attrib.Value();
+ }
+ else if ( StringEqual( p, "standalone", true, _encoding ) )
+ {
+ TiXmlAttribute attrib;
+ p = attrib.Parse( p, data, _encoding );
+ standalone = attrib.Value();
+ }
+ else
+ {
+ // Read over whatever it is.
+ while( p && *p && *p != '>' && !IsWhiteSpace( *p ) )
+ ++p;
+ }
+ }
+ return 0;
+}
+
+bool TiXmlText::Blank() const
+{
+ for ( unsigned i=0; i<value.length(); i++ )
+ if ( !IsWhiteSpace( value[i] ) )
+ return false;
+ return true;
+}
+