import urban terror bumpy q3map2 from http://code.google.com/p/urt-bumpy-q3map2/ - removed some trash files, no modifications yet

This commit is contained in:
Timothee 'TTimo' Besset 2012-05-27 18:50:03 -05:00
parent c22d17a379
commit 31286fb558
507 changed files with 162910 additions and 0 deletions

View File

@ -0,0 +1 @@
.consign

View File

@ -0,0 +1,2 @@
#include "archivelib.h"

237
tools/urt/libs/archivelib.h Normal file
View File

@ -0,0 +1,237 @@
#if !defined (INCLUDED_ARCHIVELIB_H)
#define INCLUDED_ARCHIVELIB_H
#include "debugging/debugging.h"
#include "iarchive.h"
#include "stream/filestream.h"
#include "stream/textfilestream.h"
#include "memory/allocator.h"
#include "string/string.h"
/// \brief A single-byte-reader wrapper around an InputStream.
/// Optimised for reading one byte at a time.
/// Uses a buffer to reduce the number of times the wrapped stream must be read.
template<typename InputStreamType, int SIZE = 1024>
class SingleByteInputStream
{
typedef typename InputStreamType::byte_type byte_type;
enum { c_bufferSize = SIZE };
InputStreamType& m_inputStream;
byte_type m_buffer[c_bufferSize];
byte_type* m_cur;
byte_type* m_end;
public:
SingleByteInputStream(InputStreamType& inputStream) : m_inputStream(inputStream), m_cur(m_buffer + c_bufferSize), m_end(m_cur)
{
}
bool readByte(byte_type& b)
{
if(m_cur == m_end)
{
if(m_end != m_buffer + c_bufferSize)
{
return false;
}
m_end = m_buffer + m_inputStream.read(m_buffer, c_bufferSize);
m_cur = m_buffer;
if(m_end == m_buffer)
{
return false;
}
}
b = *m_cur++;
return true;
}
};
/// \brief A binary-to-text wrapper around an InputStream.
/// Converts CRLF or LFCR line-endings to LF line-endings.
template<typename BinaryInputStreamType>
class BinaryToTextInputStream : public TextInputStream
{
SingleByteInputStream<BinaryInputStreamType> m_inputStream;
public:
BinaryToTextInputStream(BinaryInputStreamType& inputStream) : m_inputStream(inputStream)
{
}
std::size_t read(char* buffer, std::size_t length)
{
char* p = buffer;
for(;;)
{
if(length != 0 && m_inputStream.readByte(*reinterpret_cast<typename BinaryInputStreamType::byte_type*>(p)))
{
if(*p != '\r')
{
++p;
--length;
}
}
else
{
return p - buffer;
}
}
}
};
/// \brief An ArchiveFile which is stored uncompressed as part of a larger archive file.
class StoredArchiveFile : public ArchiveFile
{
CopiedString m_name;
FileInputStream m_filestream;
SubFileInputStream m_substream;
FileInputStream::size_type m_size;
public:
typedef FileInputStream::size_type size_type;
typedef FileInputStream::position_type position_type;
StoredArchiveFile(const char* name, const char* archiveName, position_type position, size_type stream_size, size_type file_size)
: m_name(name), m_filestream(archiveName), m_substream(m_filestream, position, stream_size), m_size(file_size)
{
}
static StoredArchiveFile* create(const char* name, const char* archiveName, position_type position, size_type stream_size, size_type file_size)
{
return New<StoredArchiveFile>().scalar(name, archiveName, position, stream_size, file_size);
}
void release()
{
Delete<StoredArchiveFile>().scalar(this);
}
size_type size() const
{
return m_size;
}
const char* getName() const
{
return m_name.c_str();
}
InputStream& getInputStream()
{
return m_substream;
}
};
/// \brief An ArchiveTextFile which is stored uncompressed as part of a larger archive file.
class StoredArchiveTextFile : public ArchiveTextFile
{
CopiedString m_name;
FileInputStream m_filestream;
SubFileInputStream m_substream;
BinaryToTextInputStream<SubFileInputStream> m_textStream;
public:
typedef FileInputStream::size_type size_type;
typedef FileInputStream::position_type position_type;
StoredArchiveTextFile(const char* name, const char* archiveName, position_type position, size_type stream_size)
: m_name(name), m_filestream(archiveName), m_substream(m_filestream, position, stream_size), m_textStream(m_substream)
{
}
static StoredArchiveTextFile* create(const char* name, const char* archiveName, position_type position, size_type stream_size)
{
return New<StoredArchiveTextFile>().scalar(name, archiveName, position, stream_size);
}
void release()
{
Delete<StoredArchiveTextFile>().scalar(this);
}
const char* getName() const
{
return m_name.c_str();
}
TextInputStream& getInputStream()
{
return m_textStream;
}
};
/// \brief An ArchiveFile which is stored as a single file on disk.
class DirectoryArchiveFile : public ArchiveFile
{
CopiedString m_name;
FileInputStream m_istream;
FileInputStream::size_type m_size;
public:
typedef FileInputStream::size_type size_type;
DirectoryArchiveFile(const char* name, const char* filename)
: m_name(name), m_istream(filename)
{
if(!failed())
{
m_istream.seek(0, FileInputStream::end);
m_size = m_istream.tell();
m_istream.seek(0);
}
else
{
m_size = 0;
}
}
bool failed() const
{
return m_istream.failed();
}
void release()
{
delete this;
}
size_type size() const
{
return m_size;
}
const char* getName() const
{
return m_name.c_str();
}
InputStream& getInputStream()
{
return m_istream;
}
};
/// \brief An ArchiveTextFile which is stored as a single file on disk.
class DirectoryArchiveTextFile : public ArchiveTextFile
{
CopiedString m_name;
TextFileInputStream m_inputStream;
public:
DirectoryArchiveTextFile(const char* name, const char* filename)
: m_name(name), m_inputStream(filename)
{
}
bool failed() const
{
return m_inputStream.failed();
}
void release()
{
delete this;
}
const char* getName() const
{
return m_name.c_str();
}
TextInputStream& getInputStream()
{
return m_inputStream;
}
};
#endif

View File

@ -0,0 +1,2 @@
#include "bytebool.h"

11
tools/urt/libs/bytebool.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef __BYTEBOOL__
#define __BYTEBOOL__
// defines boolean and byte types usable in both c and c++ code
// this header is not really meant for direct inclusion,
// it is used by mathlib and cmdlib
typedef enum { qfalse, qtrue } qboolean;
typedef unsigned char byte;
#endif

View File

@ -0,0 +1,2 @@
#include "bytestreamutils.h"

View File

@ -0,0 +1,100 @@
#if !defined(INCLUDED_BYTESTREAMUTILS_H)
#define INCLUDED_BYTESTREAMUTILS_H
#include <algorithm>
#if defined(_MSC_VER)
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
#else
#define _ISOC9X_SOURCE 1
#define _ISOC99_SOURCE 1
#define __USE_ISOC9X 1
#define __USE_ISOC99 1
#include <stdint.h>
#endif
template<typename InputStreamType, typename Type>
inline void istream_read_little_endian(InputStreamType& istream, Type& value)
{
istream.read(reinterpret_cast<typename InputStreamType::byte_type*>(&value), sizeof(Type));
#if defined(__BIG_ENDIAN__)
std::reverse(reinterpret_cast<typename InputStreamType::byte_type*>(&value), reinterpret_cast<typename InputStreamType::byte_type*>(&value) + sizeof(Type));
#endif
}
template<typename InputStreamType, typename Type>
inline void istream_read_big_endian(InputStreamType& istream, Type& value)
{
istream.read(reinterpret_cast<typename InputStreamType::byte_type*>(&value), sizeof(Type));
#if !defined(__BIG_ENDIAN__)
std::reverse(reinterpret_cast<typename InputStreamType::byte_type*>(&value), reinterpret_cast<typename InputStreamType::byte_type*>(&value) + sizeof(Type));
#endif
}
template<typename InputStreamType>
inline void istream_read_byte(InputStreamType& istream, typename InputStreamType::byte_type& b)
{
istream.read(&b, 1);
}
template<typename InputStreamType>
inline int16_t istream_read_int16_le(InputStreamType& istream)
{
int16_t value;
istream_read_little_endian(istream, value);
return value;
}
template<typename InputStreamType>
inline uint16_t istream_read_uint16_le(InputStreamType& istream)
{
uint16_t value;
istream_read_little_endian(istream, value);
return value;
}
template<typename InputStreamType>
inline int32_t istream_read_int32_le(InputStreamType& istream)
{
int32_t value;
istream_read_little_endian(istream, value);
return value;
}
template<typename InputStreamType>
inline uint32_t istream_read_uint32_le(InputStreamType& istream)
{
uint32_t value;
istream_read_little_endian(istream, value);
return value;
}
template<typename InputStreamType>
inline float istream_read_float32_le(InputStreamType& istream)
{
float value;
istream_read_little_endian(istream, value);
return value;
}
template<typename InputStreamType>
inline typename InputStreamType::byte_type istream_read_byte(InputStreamType& istream)
{
typename InputStreamType::byte_type b;
istream.read(&b, sizeof(typename InputStreamType::byte_type));
return b;
}
#endif

View File

@ -0,0 +1,3 @@
#include "character.h"

View File

@ -0,0 +1,27 @@
#if !defined(INCLUDED_CHARACTER_H)
#define INCLUDED_CHARACTER_H
/// \file
/// \brief Character encoding.
/// \brief Returns true if \p c is an ASCII character that can be represented with 7 bits.
inline bool char_is_ascii(char c)
{
return (c & 0x80) == 0;
}
/// \brief Returns true if \p string consists entirely of ASCII characters.
inline bool string_is_ascii(const char* string)
{
while(*string != '\0')
{
if(!char_is_ascii(*string++))
{
return false;
}
}
return true;
}
#endif

106
tools/urt/libs/cmdlib.h Normal file
View File

@ -0,0 +1,106 @@
/*
This code is based on source provided under the terms of the Id Software
LIMITED USE SOFTWARE LICENSE AGREEMENT, a copy of which is included with the
GtkRadiant sources (see LICENSE_ID). If you did not receive a copy of
LICENSE_ID, please contact Id Software immediately at info@idsoftware.com.
All changes and additions to the original source which have been developed by
other contributors (see CONTRIBUTORS) are provided under the terms of the
license the contributors choose (see LICENSE), to the extent permitted by the
LICENSE_ID. If you did not receive a copy of the contributor license,
please contact the GtkRadiant maintainers at info@gtkradiant.com immediately.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//
// start of shared cmdlib stuff
//
#ifndef __CMDLIB__
#define __CMDLIB__
#include <time.h>
// TTimo started adding portability code:
// return true if spawning was successful, false otherwise
// on win32 we have a bCreateConsole flag to create a new console or run inside the current one
//boolean Q_Exec(const char* pCmd, boolean bCreateConsole);
// execute a system command:
// cmd: the command to run
// cmdline: the command line
// NOTE TTimo following are win32 specific:
// execdir: the directory to execute in
// bCreateConsole: spawn a new console or not
// return values;
// if the spawn was fine
// TODO TTimo add functionality to track the process until it dies
bool Q_Exec(const char *cmd, char *cmdline, const char *execdir, bool bCreateConsole);
// some easy portability crap
#define access_owner_read 0400
#define access_owner_write 0200
#define access_owner_execute 0100
#define access_owner_rw_ 0600
#define access_owner_r_x 0500
#define access_owner__wx 0300
#define access_owner_rwx 0700
#define access_group_read 0040
#define access_group_write 0020
#define access_group_execute 0010
#define access_group_rw_ 0060
#define access_group_r_x 0050
#define access_group__wx 0030
#define access_group_rwx 0070
#define access_others_read 0004
#define access_others_write 0002
#define access_others_execute 0001
#define access_others_rw_ 0006
#define access_others_r_x 0005
#define access_others__wx 0003
#define access_others_rwx 0007
#define access_rwxrwxr_x (access_owner_rwx | access_group_rwx | access_others_r_x)
#define access_rwxrwxrwx (access_owner_rwx | access_group_rwx | access_others_rwx)
// Q_mkdir
// returns true if succeeded in creating directory
#ifdef WIN32
#include <direct.h>
inline bool Q_mkdir(const char* name)
{
return _mkdir(name) != -1;
}
#else
#include <sys/stat.h>
inline bool Q_mkdir(const char* name)
{
return mkdir(name, access_rwxrwxr_x) != -1;
}
#endif
inline double Sys_DoubleTime(void)
{
return clock()/ 1000.0;
}
#endif

View File

@ -0,0 +1 @@
Debug Release *.ncb *.opt *.plg *.001 *.BAK

View File

@ -0,0 +1,3 @@
*.dsp -m 'COPY' -k 'b'
*.dsw -m 'COPY' -k 'b'
*.scc -m 'COPY' -k 'b'

View File

@ -0,0 +1,133 @@
/*
This code is based on source provided under the terms of the Id Software
LIMITED USE SOFTWARE LICENSE AGREEMENT, a copy of which is included with the
GtkRadiant sources (see LICENSE_ID). If you did not receive a copy of
LICENSE_ID, please contact Id Software immediately at info@idsoftware.com.
All changes and additions to the original source which have been developed by
other contributors (see CONTRIBUTORS) are provided under the terms of the
license the contributors choose (see LICENSE), to the extent permitted by the
LICENSE_ID. If you did not receive a copy of the contributor license,
please contact the GtkRadiant maintainers at info@gtkradiant.com immediately.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//
// start of shared cmdlib stuff
//
#include "cmdlib.h"
#include <string.h>
#include <stdio.h>
#include "string/string.h"
#include "os/path.h"
#include "container/array.h"
#ifdef WIN32
#include <windows.h>
#endif
#if defined (__linux__) || defined (__APPLE__)
#include <unistd.h>
#endif
#if defined (__linux__) || defined (__APPLE__)
bool Q_Exec(const char *cmd, char *cmdline, const char *, bool)
{
char fullcmd[2048];
char *pCmd;
#ifdef _DEBUG
printf("Q_Exec damnit\n");
#endif
switch (fork())
{
case -1:
return true;
break;
case 0:
// always concat the command on linux
if (cmd)
{
strcpy(fullcmd, cmd);
}
else
fullcmd[0] = '\0';
if (cmdline)
{
strcat(fullcmd, " ");
strcat(fullcmd, cmdline);
}
pCmd = fullcmd;
while (*pCmd == ' ')
pCmd++;
#ifdef _DEBUG
printf("Running system...\n");
printf("Command: %s\n", pCmd);
#endif
system( pCmd );
#ifdef _DEBUG
printf ("system() returned\n");
#endif
_exit (0);
break;
}
return true;
}
#endif
#ifdef WIN32
// NOTE TTimo windows is VERY nitpicky about the syntax in CreateProcess
bool Q_Exec(const char *cmd, char *cmdline, const char *execdir, bool bCreateConsole)
{
PROCESS_INFORMATION ProcessInformation;
STARTUPINFO startupinfo = {0};
DWORD dwCreationFlags;
GetStartupInfo (&startupinfo);
if (bCreateConsole)
dwCreationFlags = CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS;
else
dwCreationFlags = DETACHED_PROCESS | NORMAL_PRIORITY_CLASS;
const char *pCmd;
char *pCmdline;
pCmd = cmd;
if (pCmd)
{
while (*pCmd == ' ')
pCmd++;
}
pCmdline = cmdline;
if (pCmdline)
{
while (*pCmdline == ' ')
pCmdline++;
}
if (CreateProcess(
pCmd,
pCmdline,
NULL,
NULL,
FALSE,
dwCreationFlags,
NULL,
execdir,
&startupinfo,
&ProcessInformation
))
return true;
return false;
}
#endif

View File

@ -0,0 +1,101 @@
# Microsoft Developer Studio Project File - Name="cmdlib" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=cmdlib - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "cmdlib.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "cmdlib.mak" CFG="cmdlib - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "cmdlib - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "cmdlib - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "cmdlib"
# PROP Scc_LocalPath ".."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "cmdlib - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
MTL=midl.exe
F90=df.exe
# ADD BASE F90 /include:"Release/"
# ADD F90 /include:"Release/"
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /O2 /I "..\\" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "cmdlib - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
MTL=midl.exe
F90=df.exe
# ADD BASE F90 /include:"Debug/"
# ADD F90 /include:"Debug/"
# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MDd /W3 /Z7 /Od /I "..\\" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "cmdlib - Win32 Release"
# Name "cmdlib - Win32 Debug"
# Begin Source File
SOURCE=.\CMDLIB.cpp
# End Source File
# Begin Source File
SOURCE=..\cmdlib.h
# End Source File
# End Target
# End Project

View File

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="cmdlib"
ProjectGUID="{8845C5C1-4154-425F-8643-447FADC03449}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="4"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
StringPooling="TRUE"
MinimalRebuild="TRUE"
ExceptionHandling="FALSE"
BasicRuntimeChecks="0"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
BrowseInformation="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/cmdlib.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"
IntermediateDirectory="Release"
ConfigurationType="4"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
OptimizeForWindowsApplication="TRUE"
AdditionalIncludeDirectories="../"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
StringPooling="TRUE"
ExceptionHandling="FALSE"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/cmdlib.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>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="src"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\cmdlib.cpp">
</File>
<File
RelativePath="..\cmdlib.h">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,19 @@
#include "array.h"
namespace
{
class Bleh
{
Array<int> m_array;
public:
Bleh() : m_array(16)
{
}
};
void testAutoArray()
{
Array<Bleh> array(32);
}
}

View File

@ -0,0 +1,170 @@
#if !defined(INCLUDED_CONTAINER_ARRAY_H)
#define INCLUDED_CONTAINER_ARRAY_H
#include <cstddef>
#include <algorithm>
#include "memory/allocator.h"
/// \brief An array whose size is variable at run-time.
///
/// - Resizing the array destroys all the existing elements and invalidates all iterators.
/// - Default-Constructible, Copyable, Assignable.
/// - Compatible with the containers and algorithms in the Standard Template Library (STL) - http://www.sgi.com/tech/stl/
///
/// \param Element The type to be stored in the array. Must provide a default-constructor and a copy-constructor.
/// \param Allocator A custom memory-allocator, conforming to the std::allocator interface.
template<typename Element, typename Allocator = DefaultAllocator<Element> >
class Array : public Allocator
{
std::size_t m_size;
Element* m_data;
Element* construct(std::size_t size)
{
#if 1
return New<Element, Allocator>(*this).vector(size);
#else
return new Element[size];
#endif
}
template<typename T1>
Element* construct(std::size_t size, const T1& value)
{
return New<Element, Allocator>(*this).vector(size, value);
}
void destroy(Element* data, std::size_t size)
{
#if 1
Delete<Element, Allocator>(*this).vector(data, size);
#else
delete[] data;
#endif
}
public:
typedef Element value_type;
typedef value_type* iterator;
typedef const value_type* const_iterator;
Array()
: m_size(0), m_data(0)
{
}
Array(std::size_t size)
: m_size(size), m_data(construct(size))
{
}
template<typename T1>
Array(std::size_t size, const T1& value)
: m_size(size), m_data(construct(size, value))
{
}
Array(const Array& other)
: Allocator(other), m_size(other.size()), m_data(construct(m_size))
{
std::copy(other.begin(), other.end(), begin());
}
template<typename Iterator>
Array(Iterator start, Iterator finish)
: m_size(std::distance(start, finish)), m_data(construct(m_size))
{
std::copy(start, finish, begin());
}
~Array()
{
destroy(m_data, m_size);
}
Array& operator=(const Array& other)
{
Array temp(other);
temp.swap(*this);
return *this;
}
void swap(Array& other)
{
std::swap(m_size, other.m_size);
std::swap(m_data, other.m_data);
}
iterator begin()
{
return m_data;
}
const_iterator begin() const
{
return m_data;
}
iterator end()
{
return m_data + m_size;
}
const_iterator end() const
{
return m_data + m_size;
}
value_type& operator[](std::size_t index)
{
#if defined(_DEBUG)
ASSERT_MESSAGE(index < size(), "array index out of bounds");
#endif
return m_data[index];
}
const value_type& operator[](std::size_t index) const
{
#if defined(_DEBUG)
ASSERT_MESSAGE(index < size(), "array index out of bounds");
#endif
return m_data[index];
}
value_type* data()
{
return m_data;
}
const value_type* data() const
{
return m_data;
}
std::size_t size() const
{
return m_size;
}
bool empty() const
{
return m_size == 0;
}
void resize(std::size_t count)
{
if(count != size())
{
Array temp(count);
temp.swap(*this);
}
}
void resize(std::size_t count, const value_type& value)
{
if(count != size())
{
Array temp(count, value);
temp.swap(*this);
}
}
};
namespace std
{
/// \brief Swaps the values of \p self and \p other.
/// Overloads std::swap.
template<typename Element, typename Allocator>
inline void swap(Array<Element, Allocator>& self, Array<Element, Allocator>& other)
{
self.swap(other);
}
}
#endif

View File

@ -0,0 +1,2 @@
#include "cache.h"

View File

@ -0,0 +1,177 @@
#if !defined(INCLUDED_CONTAINER_CACHE_H)
#define INCLUDED_CONTAINER_CACHE_H
#include <cstddef>
#include "container/hashtable.h"
#include "memory/allocator.h"
template<typename Type, typename Parameter>
class DefaultCreationPolicy
{
public:
Type* construct(const Parameter& parameter)
{
return New<Type>().scalar(parameter);
}
void destroy(Type* p)
{
Delete<Type>().scalar(p);
}
};
template<typename Type>
class SharedValue
{
typedef Type value_type;
typedef value_type* pointer;
typedef value_type& reference;
std::size_t m_count;
pointer m_value;
public:
SharedValue()
: m_count(0), m_value(0)
{
}
~SharedValue()
{
ASSERT_MESSAGE(m_count == 0 , "destroying a referenced object\n");
}
void set(pointer value)
{
m_value = value;
}
pointer get()
{
return m_value;
}
std::size_t increment()
{
return ++m_count;
}
std::size_t decrement()
{
ASSERT_MESSAGE(!empty(), "destroying a non-existent object\n");
return --m_count;
}
std::size_t count()
{
return m_count;
}
bool empty()
{
return m_count == 0;
}
reference operator*() const
{
ASSERT_NOTNULL(m_value);
return *m_value;
}
pointer operator->() const
{
return &(operator*());
}
};
/// \brief Caches values that are uniquely identified by a key.
///
/// - Automatically removes objects that are no longer referenced.
///
/// \param Key Uniquely identifies each element.
/// \param Cached The type to be cached. Must define a constructor that accepts \c Key.
template<typename Key, typename Cached, typename Hasher, typename KeyEqual = std::equal_to<Key>, typename CreationPolicy = DefaultCreationPolicy<Cached, Key> >
class HashedCache : public CreationPolicy
{
typedef SharedValue<Cached> Element;
typedef HashTable<Key, Element, Hasher, KeyEqual> map_type;
map_type m_map;
public:
explicit HashedCache(const CreationPolicy& creation = CreationPolicy())
: CreationPolicy(creation), m_map(256)
{
}
~HashedCache()
{
ASSERT_MESSAGE(empty(), "HashedCache::~HashedCache: not empty");
}
typedef typename map_type::iterator iterator;
typedef typename map_type::value_type value_type;
iterator begin()
{
return m_map.begin();
}
iterator end()
{
return m_map.end();
}
bool empty() const
{
return m_map.empty();
}
iterator find(const Key& key)
{
return m_map.find(key);
}
void capture(iterator i)
{
(*i).value.increment();
}
void release(iterator i)
{
if((*i).value.decrement() == 0)
{
CreationPolicy::destroy((*i).value.get());
m_map.erase(i);
}
}
#if 1
Element& capture(const Key& key)
{
Element& elem = m_map[key];
if(elem.increment() == 1)
{
elem.set(CreationPolicy::construct(key));
}
return elem;
}
#else
value_type& capture(const Key& key)
{
iterator i = m_map.find(key);
if(i == m_map.end())
{
Element element;
element.set(CreationPolicy::construct(key));
i = m_map.insert(key, element);
}
(*i).value.increment();
return (*i);
}
#endif
void release(const Key& key)
{
iterator i = m_map.find(key);
ASSERT_MESSAGE(i != m_map.end(), "releasing a non-existent object\n");
release(i);
}
void clear()
{
m_map.clear();
}
};
#endif

View File

@ -0,0 +1,3 @@
#include "container.h"

View File

@ -0,0 +1,326 @@
#if !defined(INCLUDED_CONTAINER_CONTAINER_H)
#define INCLUDED_CONTAINER_CONTAINER_H
#include <list>
#include <set>
#include "generic/static.h"
/// \brief A single-value container, which can either be empty or full.
template<typename Type>
class Single
{
Type* m_value;
public:
Single() : m_value(0)
{
}
bool empty()
{
return m_value == 0;
}
Type* insert(const Type& other)
{
m_value = new Type(other);
return m_value;
}
void clear()
{
delete m_value;
m_value = 0;
}
Type& get()
{
//ASSERT_MESSAGE(!empty(), "Single: must be initialised before being accessed");
return *m_value;
}
const Type& get() const
{
//ASSERT_MESSAGE(!empty(), "Single: must be initialised before being accessed");
return *m_value;
}
};
/// \brief An adaptor to make std::list into a Unique Sequence - which cannot contain the same value more than once.
/// \param Value Uniquely identifies itself. Must provide a copy-constructor and an equality operator.
template<typename Value>
class UnsortedSet
{
typedef typename std::list<Value> Values;
Values m_values;
public:
typedef typename Values::iterator iterator;
typedef typename Values::const_iterator const_iterator;
typedef typename Values::reverse_iterator reverse_iterator;
typedef typename Values::const_reverse_iterator const_reverse_iterator;
iterator begin()
{
return m_values.begin();
}
const_iterator begin() const
{
return m_values.begin();
}
iterator end()
{
return m_values.end();
}
const_iterator end() const
{
return m_values.end();
}
reverse_iterator rbegin()
{
return m_values.rbegin();
}
const_reverse_iterator rbegin() const
{
return m_values.rbegin();
}
reverse_iterator rend()
{
return m_values.rend();
}
const_reverse_iterator rend() const
{
return m_values.rend();
}
bool empty() const
{
return m_values.empty();
}
std::size_t size() const
{
return m_values.size();
}
void clear()
{
m_values.clear();
}
void swap(UnsortedSet& other)
{
std::swap(m_values, other.m_values);
}
iterator insert(const Value& value)
{
ASSERT_MESSAGE(find(value) == end(), "UnsortedSet::insert: already added");
m_values.push_back(value);
return --end();
}
void erase(const Value& value)
{
iterator i = find(value);
ASSERT_MESSAGE(i != end(), "UnsortedSet::erase: not found");
m_values.erase(i);
}
iterator find(const Value& value)
{
return std::find(begin(), end(), value);
}
};
namespace std
{
/// \brief Swaps the values of \p self and \p other.
/// Overloads std::swap.
template<typename Value>
inline void swap(UnsortedSet<Value>& self, UnsortedSet<Value>& other)
{
self.swap(other);
}
}
/// An adaptor to make std::list into a Unique Associative Sequence - which cannot contain the same value more than once.
/// Key: Uniquely identifies a value. Must provide a copy-constructor and an equality operator.
/// Value: Must provide a copy-constructor.
template<typename Key, typename Value>
class UnsortedMap
{
typedef typename std::list< std::pair<Key, Value> > Values;
Values m_values;
public:
typedef typename Values::value_type value_type;
typedef typename Values::iterator iterator;
typedef typename Values::const_iterator const_iterator;
iterator begin()
{
return m_values.begin();
}
const_iterator begin() const
{
return m_values.begin();
}
iterator end()
{
return m_values.end();
}
const_iterator end() const
{
return m_values.end();
}
bool empty() const
{
return m_values.empty();
}
std::size_t size() const
{
return m_values.size();
}
void clear()
{
m_values.clear();
}
iterator insert(const value_type& value)
{
ASSERT_MESSAGE(find(value.first) == end(), "UnsortedMap::insert: already added");
m_values.push_back(value);
return --m_values.end();
}
void erase(const Key& key)
{
iterator i = find(key);
ASSERT_MESSAGE(i != end(), "UnsortedMap::erase: not found");
erase(i);
}
void erase(iterator i)
{
m_values.erase(i);
}
iterator find(const Key& key)
{
for(iterator i = m_values.begin(); i != m_values.end(); ++i)
{
if((*i).first == key)
{
return i;
}
}
return m_values.end();
}
const_iterator find(const Key& key) const
{
for(const_iterator i = m_values.begin(); i != m_values.end(); ++i)
{
if((*i).first == key)
{
return i;
}
}
return m_values.end();
}
Value& operator[](const Key& key)
{
iterator i = find(key);
if(i != end())
{
return (*i).second;
}
m_values.push_back(Values::value_type(key, Value()));
return m_values.back().second;
}
};
/// An adaptor to assert when duplicate values are added, or non-existent values removed from a std::set.
template<typename Value>
class UniqueSet
{
typedef std::set<Value> Values;
Values m_values;
public:
typedef typename Values::iterator iterator;
typedef typename Values::const_iterator const_iterator;
typedef typename Values::reverse_iterator reverse_iterator;
typedef typename Values::const_reverse_iterator const_reverse_iterator;
iterator begin()
{
return m_values.begin();
}
const_iterator begin() const
{
return m_values.begin();
}
iterator end()
{
return m_values.end();
}
const_iterator end() const
{
return m_values.end();
}
reverse_iterator rbegin()
{
return m_values.rbegin();
}
const_reverse_iterator rbegin() const
{
return m_values.rbegin();
}
reverse_iterator rend()
{
return m_values.rend();
}
const_reverse_iterator rend() const
{
return m_values.rend();
}
bool empty() const
{
return m_values.empty();
}
std::size_t size() const
{
return m_values.size();
}
void clear()
{
m_values.clear();
}
void swap(UniqueSet& other)
{
std::swap(m_values, other.m_values);
}
iterator insert(const Value& value)
{
std::pair<iterator, bool> result = m_values.insert(value);
ASSERT_MESSAGE(result.second, "UniqueSet::insert: already added");
return result.first;
}
void erase(const Value& value)
{
iterator i = find(value);
ASSERT_MESSAGE(i != end(), "UniqueSet::erase: not found");
m_values.erase(i);
}
iterator find(const Value& value)
{
return std::find(begin(), end(), value);
}
};
namespace std
{
/// \brief Swaps the values of \p self and \p other.
/// Overloads std::swap.
template<typename Value>
inline void swap(UniqueSet<Value>& self, UniqueSet<Value>& other)
{
self.swap(other);
}
}
#endif

View File

@ -0,0 +1,2 @@
#include "hashfunc.h"

View File

@ -0,0 +1,413 @@
#if !defined(INCLUDED_CONTAINER_HASHFUNC_H)
#define INCLUDED_CONTAINER_HASHFUNC_H
/*
--------------------------------------------------------------------
lookup2.c, by Bob Jenkins, December 1996, Public Domain.
hash(), hash2(), hash3, and mix() are externally useful functions.
Routines to test the hash are included if SELF_TEST is defined.
You can use this free for any purpose. It has no warranty.
--------------------------------------------------------------------
*/
#include <cctype>
#include "string/string.h"
#include "container/array.h"
typedef unsigned long int ub4; /* unsigned 4-byte quantities */
typedef unsigned char ub1;
inline ub1 ub1_as_ub1_nocase(ub1 byte)
{
return std::tolower(byte);
}
inline ub4 ub1x4_as_ub4_nocase(const ub1 bytes[4])
{
ub4 result;
reinterpret_cast<ub1*>(&result)[0] = ub1_as_ub1_nocase(bytes[0]);
reinterpret_cast<ub1*>(&result)[1] = ub1_as_ub1_nocase(bytes[1]);
reinterpret_cast<ub1*>(&result)[2] = ub1_as_ub1_nocase(bytes[2]);
reinterpret_cast<ub1*>(&result)[3] = ub1_as_ub1_nocase(bytes[3]);
return result;
}
class ub1_default_traits
{
public:
static ub1 as_ub1(ub1 byte)
{
return byte;
}
};
class ub1_nocase_traits
{
public:
static ub1 as_ub1(ub1 byte)
{
return ub1_as_ub1_nocase(byte);
}
};
class ub1x4_default_traits
{
public:
static ub4 as_ub4(const ub1 bytes[4])
{
return *reinterpret_cast<const ub4*>(bytes);
}
};
class ub1x4_nocase_traits
{
public:
static ub4 as_ub4(const ub1 bytes[4])
{
return ub1x4_as_ub4_nocase(bytes);
}
};
class ub4_default_traits
{
public:
static ub4 as_ub4(ub4 i)
{
return i;
}
};
class ub4_nocase_traits
{
public:
static ub4 as_ub4(ub4 i)
{
return ub1x4_as_ub4_nocase(reinterpret_cast<const ub1*>(&i));
}
};
#define hashsize(n) ((ub4)1<<(n))
#define hashmask(n) (hashsize(n)-1)
/*
--------------------------------------------------------------------
mix -- mix 3 32-bit values reversibly.
For every delta with one or two bit set, and the deltas of all three
high bits or all three low bits, whether the original value of a,b,c
is almost all zero or is uniformly distributed,
* If mix() is run forward or backward, at least 32 bits in a,b,c
have at least 1/4 probability of changing.
* If mix() is run forward, every bit of c will change between 1/3 and
2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
mix() was built out of 36 single-cycle latency instructions in a
structure that could supported 2x parallelism, like so:
a -= b;
a -= c; x = (c>>13);
b -= c; a ^= x;
b -= a; x = (a<<8);
c -= a; b ^= x;
c -= b; x = (b>>13);
...
Unfortunately, superscalar Pentiums and Sparcs can't take advantage
of that parallelism. They've also turned some of those single-cycle
latency instructions into multi-cycle latency instructions. Still,
this is the fastest good hash I could find. There were about 2^^68
to choose from. I only looked at a billion or so.
--------------------------------------------------------------------
*/
#define mix(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<<8); \
c -= a; c -= b; c ^= (b>>13); \
a -= b; a -= c; a ^= (c>>12); \
b -= c; b -= a; b ^= (a<<16); \
c -= a; c -= b; c ^= (b>>5); \
a -= b; a -= c; a ^= (c>>3); \
b -= c; b -= a; b ^= (a<<10); \
c -= a; c -= b; c ^= (b>>15); \
}
/* same, but slower, works on systems that might have 8 byte ub4's */
#define mix2(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<< 8); \
c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \
a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \
b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \
c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \
a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \
b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \
c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \
}
/*
--------------------------------------------------------------------
hash() -- hash a variable-length key into a 32-bit value
k : the key (the unaligned variable-length array of bytes)
len : the length of the key, counting by bytes
level : can be any 4-byte value
Returns a 32-bit value. Every bit of the key affects every bit of
the return value. Every 1-bit and 2-bit delta achieves avalanche.
About 36+6len instructions.
The best hash table sizes are powers of 2. There is no need to do
mod a prime (mod is sooo slow!). If you need less than 32 bits,
use a bitmask. For example, if you need only 10 bits, do
h = (h & hashmask(10));
In which case, the hash table should have hashsize(10) elements.
If you are hashing n strings (ub1 **)k, do it like this:
for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
code any way you wish, private, educational, or commercial. It's free.
See http://burlteburtle.net/bob/hash/evahash.html
Use for hash table lookup, or anything where one collision in 2^32 is
acceptable. Do NOT use for cryptographic purposes.
--------------------------------------------------------------------
*/
template<typename UB1Traits, typename UB4x1Traits>
inline ub4 hash(
const ub1 *k, /* the key */
ub4 length, /* the length of the key */
ub4 initval, /* the previous hash, or an arbitrary value */
const UB1Traits& ub1traits,
const UB4x1Traits& ub4x1traits
)
{
register ub4 a,b,c,len;
/* Set up the internal state */
len = length;
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
c = initval; /* the previous hash value */
/*---------------------------------------- handle most of the key */
while (len >= 12)
{
a += (k[0] +((ub4)UB1Traits::as_ub1(k[1])<<8) +((ub4)UB1Traits::as_ub1(k[2])<<16) +((ub4)UB1Traits::as_ub1(k[3])<<24));
b += (k[4] +((ub4)UB1Traits::as_ub1(k[5])<<8) +((ub4)UB1Traits::as_ub1(k[6])<<16) +((ub4)UB1Traits::as_ub1(k[7])<<24));
c += (k[8] +((ub4)UB1Traits::as_ub1(k[9])<<8) +((ub4)UB1Traits::as_ub1(k[10])<<16)+((ub4)UB1Traits::as_ub1(k[11])<<24));
mix(a,b,c);
k += 12; len -= 12;
}
/*------------------------------------- handle the last 11 bytes */
c += length;
switch(len) /* all the case statements fall through */
{
case 11: c += ((ub4)UB1Traits::as_ub1(k[10]) << 24);
case 10: c += ((ub4)UB1Traits::as_ub1(k[9]) << 16);
case 9 : c += ((ub4)UB1Traits::as_ub1(k[8]) << 8);
/* the first byte of c is reserved for the length */
case 8 : b += ((ub4)UB1Traits::as_ub1(k[7]) << 24);
case 7 : b += ((ub4)UB1Traits::as_ub1(k[6]) << 16);
case 6 : b += ((ub4)UB1Traits::as_ub1(k[5]) << 8);
case 5 : b += UB1Traits::as_ub1(k[4]);
case 4 : a += ((ub4)UB1Traits::as_ub1(k[3]) << 24);
case 3 : a += ((ub4)UB1Traits::as_ub1(k[2]) << 16);
case 2 : a += ((ub4)UB1Traits::as_ub1(k[1]) << 8);
case 1 : a += UB1Traits::as_ub1(k[0]);
/* case 0: nothing left to add */
}
mix(a,b,c);
/*-------------------------------------------- report the result */
return c;
}
/*
--------------------------------------------------------------------
This works on all machines. hash2() is identical to hash() on
little-endian machines, except that the length has to be measured
in ub4s instead of bytes. It is much faster than hash(). It
requires
-- that the key be an array of ub4's, and
-- that all your machines have the same endianness, and
-- that the length be the number of ub4's in the key
--------------------------------------------------------------------
*/
template<typename UB4Traits>
inline ub4 hash2(
const ub4 *k, /* the key */
ub4 length, /* the length of the key, in ub4s */
ub4 initval, /* the previous hash, or an arbitrary value */
const UB4Traits& ub4traits
)
{
register ub4 a,b,c,len;
/* Set up the internal state */
len = length;
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
c = initval; /* the previous hash value */
/*---------------------------------------- handle most of the key */
while (len >= 3)
{
a += UB4Traits::as_ub4(k[0]);
b += UB4Traits::as_ub4(k[1]);
c += UB4Traits::as_ub4(k[2]);
mix(a,b,c);
k += 3; len -= 3;
}
/*-------------------------------------- handle the last 2 ub4's */
c += length;
switch(len) /* all the case statements fall through */
{
/* c is reserved for the length */
case 2 : b += UB4Traits::as_ub4(k[1]);
case 1 : a += UB4Traits::as_ub4(k[0]);
/* case 0: nothing left to add */
}
mix(a,b,c);
/*-------------------------------------------- report the result */
return c;
}
typedef ub4 hash_t;
inline hash_t hash_ub1(const ub1* key, std::size_t len, hash_t previous = 0)
{
return hash(key, ub4(len), previous, ub1_default_traits(), ub1x4_default_traits());
}
inline hash_t hash_ub1_nocase(const ub1* key, std::size_t len, hash_t previous = 0)
{
return hash(key, ub4(len), previous, ub1_nocase_traits(), ub1x4_nocase_traits());
}
template<typename UB4Traits>
inline hash_t hash_ub4(const ub4* key, std::size_t len, const UB4Traits& traits, hash_t previous = 0)
{
return hash2(key,ub4(len), previous, traits);
}
inline ub4 hash_combine(ub4 left, ub4 right)
{
return hash_ub1(reinterpret_cast<const ub1*>(&left), 4, right);
}
template<typename POD>
inline hash_t pod_hash(const POD& pod)
{
return hash_ub1(reinterpret_cast<const ub1*>(&pod), sizeof(POD));
}
inline hash_t string_hash(const char* string, hash_t previous = 0)
{
return hash_ub1(reinterpret_cast<const ub1*>(string), string_length(string), previous);
}
inline hash_t string_hash_nocase(const char* string, hash_t previous = 0)
{
return hash_ub1_nocase(reinterpret_cast<const ub1*>(string), string_length(string), previous);
}
struct HashString
{
typedef hash_t hash_type;
hash_type operator()(const CopiedString& string) const
{
return string_hash(string.c_str());
}
};
struct HashStringNoCase
{
typedef hash_t hash_type;
hash_type operator()(const CopiedString& string) const
{
return string_hash_nocase(string.c_str());
}
};
/// \brief Length of a string in ub4.
/// "wibble" (6) gives 2,
/// "and" (3) gives 1,
/// "bleh" (4) gives 2
inline std::size_t string_length_ub4(const char* string)
{
return ((string_length(string)>>2)+1)<<2;
}
/// \brief Hashable key type that stores a string as an array of ub4 - making hashing faster.
/// Also caches the 32-bit result of the hash to speed up comparison of keys.
template<typename UB4Traits = ub4_default_traits>
class HashKey
{
Array<ub4> m_key;
hash_t m_hash;
void copy(const HashKey& other)
{
std::copy(other.m_key.begin(), other.m_key.end(), m_key.begin());
m_hash = other.m_hash;
}
void copy(const char* string)
{
strncpy(reinterpret_cast<char*>(m_key.data()), string, m_key.size());
for(Array<ub4>::iterator i = m_key.begin(); i != m_key.end(); ++i)
{
*i = UB4Traits::as_ub4(*i);
}
m_hash = hash_ub4(m_key.data(), m_key.size(), ub4_default_traits());
}
bool equal(const HashKey& other) const
{
return m_hash == other.m_hash && m_key.size() == other.m_key.size()
&& std::equal(m_key.begin(), m_key.end(), other.m_key.begin());
}
public:
HashKey(const HashKey& other) : m_key(other.m_key.size())
{
copy(other);
}
HashKey(const char* string) : m_key(string_length_ub4(string))
{
copy(string);
}
HashKey& operator=(const char* string)
{
m_key.resize(string_length_ub4(string));
copy(string);
return *this;
}
bool operator==(const HashKey& other) const
{
return equal(other);
}
bool operator!=(const HashKey& other) const
{
return !equal(other);
}
hash_t hash() const
{
return m_hash;
}
#if 0
const char* c_str() const
{
return reinterpret_cast<const char*>(m_key.data());
}
#endif
};
/// \brief Hash function to use with HashKey.
struct HashKeyHasher
{
typedef hash_t hash_type;
hash_type operator()(const HashKey<ub4_default_traits>& key) const
{
return key.hash();
}
};
#endif

View File

@ -0,0 +1,45 @@
#include "hashtable.h"
#if defined(_DEBUG) || defined(DOXYGEN)
#include "hashfunc.h"
namespace ExampleHashTable
{
void testStuff()
{
// HashTable example
typedef HashTable<CopiedString, int, HashString> MyHashTable;
MyHashTable hashtable;
hashtable["bleh"] = 5;
hashtable.insert("blah", 17);
hashtable["foo"] = 99;
hashtable.insert("bar", 23);
int bleh = (*hashtable.find("bleh")).value; // 5
int blah = hashtable["blah"]; // 17
hashtable.erase("foo");
MyHashTable::iterator barIter = hashtable.find("bar");
hashtable.erase(barIter);
for(MyHashTable::iterator i = hashtable.begin(); i != hashtable.end(); ++i)
{
if((*i).key != "bleh")
{
++hashtable["count"]; // insertion does not invalidate iterators
}
}
// end example
}
struct Always
{
Always()
{
testStuff();
}
} always;
}
#endif

View File

@ -0,0 +1,455 @@
#if !defined(INCLUDED_CONTAINER_HASHTABLE_H)
#define INCLUDED_CONTAINER_HASHTABLE_H
#include <cstddef>
#include <algorithm>
#include <functional>
#include "debugging/debugging.h"
namespace HashTableDetail
{
inline std::size_t next_power_of_two(std::size_t size)
{
std::size_t result = 1;
while(result < size)
{
result <<= 1;
}
return result;
}
struct BucketNodeBase
{
BucketNodeBase* next;
BucketNodeBase* prev;
};
inline void list_initialise(BucketNodeBase& self)
{
self.next = self.prev = &self;
}
inline void list_swap(BucketNodeBase& self, BucketNodeBase& other)
{
BucketNodeBase tmp(self);
if(other.next == &other)
{
list_initialise(self);
}
else
{
self = other;
self.next->prev = self.prev->next = &self;
}
if(tmp.next == &self)
{
list_initialise(other);
}
else
{
other = tmp;
other.next->prev = other.prev->next = &other;
}
}
inline void node_link(BucketNodeBase* node, BucketNodeBase* next)
{
node->next = next;
node->prev = next->prev;
next->prev = node;
node->prev->next = node;
}
inline void node_unlink(BucketNodeBase* node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
}
template<typename Key, typename Value>
struct KeyValue
{
const Key key;
Value value;
KeyValue(const Key& key_, const Value& value_)
: key(key_), value(value_)
{
}
};
template<typename Key, typename Value, typename Hash>
struct BucketNode : public BucketNodeBase
{
Hash m_hash;
KeyValue<Key, Value> m_value;
BucketNode(Hash hash, const Key& key, const Value& value)
: m_hash(hash), m_value(key, value)
{
}
BucketNode* getNext()
{
return static_cast<BucketNode*>(next);
}
BucketNode* getPrev()
{
return static_cast<BucketNode*>(prev);
}
};
template<typename Key, typename Value, typename Hash>
class BucketIterator
{
typedef BucketNode<Key, Value, Hash> Node;
Node* m_node;
void increment()
{
m_node = m_node->getNext();
}
public:
typedef std::forward_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
typedef difference_type distance_type;
typedef KeyValue<Key, Value> value_type;
typedef value_type* pointer;
typedef value_type& reference;
BucketIterator(Node* node) : m_node(node)
{
}
Node* node()
{
return m_node;
}
bool operator==(const BucketIterator& other) const
{
return m_node == other.m_node;
}
bool operator!=(const BucketIterator& other) const
{
return !operator==(other);
}
BucketIterator& operator++()
{
increment();
return *this;
}
BucketIterator operator++(int)
{
BucketIterator tmp = *this;
increment();
return tmp;
}
value_type& operator*()
{
return m_node->m_value;
}
value_type* operator->()
{
return &(operator*());
}
};
}
/// A hash-table container which maps keys to values.
///
/// - Inserting or removing elements does not invalidate iterators.
/// - Inserting or retrieving an element for a given key takes O(1) time on average.
/// - Elements are stored in no particular order.
///
/// \param Key Uniquely identifies a value. Must provide a copy-constructor.
/// \param Value The value to be stored . Must provide a default-constructor and a copy-constructor.
/// \param Hasher Must provide 'std::size_t operator()(const Key&) const' which always returns the same result if the same argument is given.
/// \param KeyEqual Must provide 'bool operator==(const Key&, const Key&) const' which returns true only if both arguments are equal.
///
/// \dontinclude container/hashtable.cpp
/// \skipline HashTable example
/// \until end example
template<typename Key, typename Value, typename Hasher, typename KeyEqual = std::equal_to<Key> >
class HashTable : private KeyEqual, private Hasher
{
typedef typename Hasher::hash_type hash_type;
typedef HashTableDetail::KeyValue<Key, Value> KeyValue;
typedef HashTableDetail::BucketNode<Key, Value, hash_type> BucketNode;
inline BucketNode* node_create(hash_type hash, const Key& key, const Value& value)
{
return new BucketNode(hash, key, value);
}
inline void node_destroy(BucketNode* node)
{
delete node;
}
typedef BucketNode* Bucket;
static Bucket* buckets_new(std::size_t count)
{
Bucket* buckets = new Bucket[count];
std::uninitialized_fill(buckets, buckets + count, Bucket(0));
return buckets;
}
static void buckets_delete(Bucket* buckets)
{
delete[] buckets;
}
std::size_t m_bucketCount;
Bucket* m_buckets;
std::size_t m_size;
HashTableDetail::BucketNodeBase m_list;
BucketNode* getFirst()
{
return static_cast<BucketNode*>(m_list.next);
}
BucketNode* getLast()
{
return static_cast<BucketNode*>(&m_list);
}
public:
typedef KeyValue value_type;
typedef HashTableDetail::BucketIterator<Key, Value, hash_type> iterator;
private:
void initialise()
{
list_initialise(m_list);
}
hash_type hashKey(const Key& key)
{
return Hasher::operator()(key);
}
std::size_t getBucketId(hash_type hash) const
{
return hash & (m_bucketCount - 1);
}
Bucket& getBucket(hash_type hash)
{
return m_buckets[getBucketId(hash)];
}
BucketNode* bucket_find(Bucket bucket, hash_type hash, const Key& key)
{
std::size_t bucketId = getBucketId(hash);
for(iterator i(bucket); i != end(); ++i)
{
hash_type nodeHash = i.node()->m_hash;
if(getBucketId(nodeHash) != bucketId)
{
return 0;
}
if(nodeHash == hash && KeyEqual::operator()((*i).key, key))
{
return i.node();
}
}
return 0;
}
BucketNode* bucket_insert(Bucket& bucket, BucketNode* node)
{
// link node into list
node_link(node, bucket_next(bucket));
bucket = node;
return node;
}
BucketNode* bucket_next(Bucket& bucket)
{
Bucket* end = m_buckets + m_bucketCount;
for(Bucket* i = &bucket; i != end; ++i)
{
if(*i != 0)
{
return *i;
}
}
return getLast();
}
void buckets_resize(std::size_t count)
{
BucketNode* first = getFirst();
BucketNode* last = getLast();
buckets_delete(m_buckets);
m_bucketCount = count;
m_buckets = buckets_new(m_bucketCount);
initialise();
for(BucketNode* i = first; i != last;)
{
BucketNode* node = i;
i = i->getNext();
bucket_insert(getBucket((*node).m_hash), node);
}
}
void size_increment()
{
if(m_size == m_bucketCount)
{
buckets_resize(m_bucketCount == 0 ? 8 : m_bucketCount << 1);
}
++m_size;
}
void size_decrement()
{
--m_size;
}
HashTable(const HashTable& other);
HashTable& operator=(const HashTable& other);
public:
HashTable() : m_bucketCount(0), m_buckets(0), m_size(0)
{
initialise();
}
HashTable(std::size_t bucketCount) : m_bucketCount(HashTableDetail::next_power_of_two(bucketCount)), m_buckets(buckets_new(m_bucketCount)), m_size(0)
{
initialise();
}
~HashTable()
{
for(BucketNode* i = getFirst(); i != getLast();)
{
BucketNode* node = i;
i = i->getNext();
node_destroy(node);
}
buckets_delete(m_buckets);
}
iterator begin()
{
return iterator(getFirst());
}
iterator end()
{
return iterator(getLast());
}
bool empty() const
{
return m_size == 0;
}
std::size_t size() const
{
return m_size;
}
/// \brief Returns an iterator pointing to the value associated with \p key if it is contained by the hash-table, else \c end().
iterator find(const Key& key)
{
hash_type hash = hashKey(key);
if(m_bucketCount != 0)
{
Bucket bucket = getBucket(hash);
if(bucket != 0)
{
BucketNode* node = bucket_find(bucket, hash, key);
if(node != 0)
{
return iterator(node);
}
}
}
return end();
}
/// \brief Adds \p value to the hash-table associated with \p key if it does not exist, or replaces the current value associated with \p key.
iterator insert(const Key& key, const Value& value)
{
hash_type hash = hashKey(key);
if(m_bucketCount != 0)
{
Bucket& bucket = getBucket(hash);
if(bucket != 0)
{
BucketNode* node = bucket_find(bucket, hash, key);
if(node != 0)
{
node->m_value.value = value;
return iterator(node);
}
}
}
size_increment();
return iterator(bucket_insert(getBucket(hash), node_create(hash, key, value)));
}
/// \brief Removes the value pointed to by \p i from the hash-table.
///
/// \p i must be a deferenceable iterator into the hash-table.
void erase(iterator i)
{
Bucket& bucket = getBucket(i.node()->m_hash);
BucketNode* node = i.node();
// if this was the last node in the bucket
if(bucket == node)
{
bucket = (node->getNext() == getLast() || &getBucket(node->getNext()->m_hash) != &bucket) ? 0 : node->getNext();
}
node_unlink(node);
ASSERT_MESSAGE(node != 0, "tried to erase a non-existent key/value");
node_destroy(node);
size_decrement();
}
/// \brief Returns the value identified by \p key if it is contained by the hash-table, else inserts and returns a new default-constructed value associated with \p key.
Value& operator[](const Key& key)
{
hash_type hash = hashKey(key);
if(m_bucketCount != 0)
{
Bucket& bucket = getBucket(hash);
if(bucket != 0)
{
BucketNode* node = bucket_find(bucket, hash, key);
if(node != 0)
{
return node->m_value.value;
}
}
}
size_increment();
return bucket_insert(getBucket(hash), node_create(hash, key, Value()))->m_value.value;
}
/// \brief Removes the value associated with \p key from the hash-table.
void erase(const Key& key)
{
erase(find(key));
}
/// \brief Swaps the contents of the hash-table with \p other.
void swap(HashTable& other)
{
std::swap(m_buckets, other.m_buckets);
std::swap(m_bucketCount, other.m_bucketCount);
std::swap(m_size, other.m_size);
HashTableDetail::list_swap(m_list, other.m_list);
}
/// \brief Removes all values from the hash-table.
void clear()
{
HashTable tmp;
tmp.swap(*this);
}
};
#endif

View File

@ -0,0 +1,3 @@
#include "stack.h"

View File

@ -0,0 +1,219 @@
#if !defined(INCLUDED_CONTAINER_STACK_H)
#define INCLUDED_CONTAINER_STACK_H
#include "memory/allocator.h"
#include <algorithm>
/// \brief A stack whose storage capacity is variable at run-time. Similar to std::vector.
///
/// - Pushing or popping elements is a constant-time operation (on average).
/// - The storage capacity of the stack will grow when a new element is added beyond the current capacity. Iterators are invalidated when the storage capacity grows.
/// - DefaultConstructible, Copyable, Assignable.
/// - Compatible with the containers and algorithms in the Standard Template Library (STL) - http://www.sgi.com/tech/stl/
///
/// \param Type: The type to be stored in the stack. Must provide a copy-constructor.
template<typename Type>
class Stack : public DefaultAllocator<Type>
{
typedef DefaultAllocator<Type> Allocator;
enum
{
DEFAULT_CAPACITY = 4,
};
typedef Type* pointer;
typedef const Type* const_pointer;
public:
typedef const_pointer const_iterator;
private:
pointer m_data;
pointer m_end;
std::size_t m_capacity;
void insert(const Type& value)
{
Allocator::construct(m_end++, value);
}
void insert_overflow(const Type& value)
{
const std::size_t new_capacity = (m_capacity) ? m_capacity + m_capacity : std::size_t(DEFAULT_CAPACITY);
const pointer new_data = Allocator::allocate(new_capacity);
const pointer new_end = std::copy(m_data, m_end, new_data);
destroy();
Allocator::deallocate(m_data, m_capacity);
m_capacity = new_capacity;
m_data = new_data;
m_end = new_end;
insert(value);
}
void destroy()
{
for(pointer p = m_data; p != m_end; ++p)
{
Allocator::destroy(p);
}
}
void construct(const Stack& other)
{
pointer p = m_data;
for(const_iterator i = other.begin(); i != other.end(); ++i)
{
Allocator::construct(p++, *i);
}
}
public:
Stack() :
m_data(0),
m_end(0),
m_capacity(0)
{
}
Stack(const Type& value) :
m_data(0),
m_end(0),
m_capacity(0)
{
push(value);
}
Stack(const Stack& other) :
DefaultAllocator<Type>(other)
{
m_capacity = other.m_capacity;
m_data = Allocator::allocate(m_capacity);
construct(other);
m_end = m_data + other.size();
}
~Stack()
{
destroy();
Allocator::deallocate(m_data, m_capacity);
}
const_iterator begin() const
{
return m_data;
}
const_iterator end() const
{
return m_end;
}
bool empty() const
{
return end() == begin();
}
void clear()
{
destroy();
m_end = m_data;
}
std::size_t size() const
{
return m_end - m_data;
}
Type operator[](const std::size_t i) const
{
return m_data[i];
}
/// \brief Pushes \p value onto the stack at the top element. If reserved storage is insufficient for the new element, this will invalidate all iterators.
void push(const Type& value)
{
if(size() == m_capacity)
{
insert_overflow(value);
}
else
{
insert(value);
}
}
/// \brief Removes the top element of the stack.
void pop()
{
Allocator::destroy(--m_end);
}
/// \brief Returns the top element of the mutable stack.
Type& top()
{
return *(m_end-1);
}
/// \brief Returns the top element of the non-mutable stack.
const Type& top() const
{
return *(m_end-1);
}
/// \brief Returns the element below the top element of the mutable stack.
Type& parent()
{
return *(m_end-2);
}
/// \brief Returns the element below the top element of the non-mutable stack.
const Type& parent() const
{
return *(m_end-2);
}
/// \brief Swaps the values of this stack and \p other.
void swap(Stack& other)
{
std::swap(m_data, other.m_data);
std::swap(m_end, other.m_end);
std::swap(m_capacity, other.m_capacity);
}
#if 1 // use copy-swap technique
Stack& operator=(const Stack& other)
{
Stack temp(other);
temp.swap(*this);
return *this;
}
#else // avoids memory allocation if capacity is already sufficient.
Stack& operator=(const Stack& other)
{
if(&other != this)
{
destroy();
if(other.size() > m_capacity)
{
Allocator::deallocate(m_data, m_capacity);
m_capacity = other.m_capacity;
m_data = Allocator::allocate(m_capacity);
}
m_end = m_data + other.size();
construct(other);
}
return *this;
}
#endif
};
/// \brief Returns true if \p self is lexicographically less than \p other.
template<typename Type>
inline bool operator<(const Stack<Type>& self, const Stack<Type>& other)
{
return std::lexicographical_compare(self.begin(), self.end(), other.begin(), other.end());
}
namespace std
{
/// \brief Swaps the values of \p self and \p other.
/// Overloads std::swap().
template<typename Type>
inline void swap(Stack<Type>& self, Stack<Type>& other)
{
self.swap(other);
}
}
#endif

View File

@ -0,0 +1,3 @@
#include "convert.h"

285
tools/urt/libs/convert.h Normal file
View File

@ -0,0 +1,285 @@
#if !defined(INCLUDED_CONVERT_H)
#define INCLUDED_CONVERT_H
/// \file
/// \brief Character encoding conversion.
#include "debugging/debugging.h"
#include <algorithm>
#include <glib/gunicode.h>
#include <glib/gconvert.h>
#include "character.h"
/// \brief Returns the number of bytes required to represent \p character in UTF-8 encoding.
inline std::size_t utf8_character_length(const char* character)
{
if((*character & 0xE0) == 0xC0) // 110xxxxx
{
return 2;
}
else if((*character & 0xF0) == 0xE0) // 1110xxxx
{
return 3;
}
else if((*character & 0xF8) == 0xF0) // 11110xxx
{
return 4;
}
else if((*character & 0xFC) == 0xF8) // 111110xx
{
return 5;
}
else if((*character & 0xFE) == 0xFC) // 1111110x
{
return 6;
}
ERROR_MESSAGE("");
return 0;
}
struct UTF8Character
{
const char* buffer;
std::size_t length;
UTF8Character() : buffer(0), length(0)
{
}
UTF8Character(const char* bytes) : buffer(bytes), length(utf8_character_length(bytes))
{
}
};
inline bool operator<(const UTF8Character& self, const UTF8Character& other)
{
return std::lexicographical_compare(self.buffer, self.buffer + self.length, other.buffer, other.buffer + other.length);
}
/// \brief Writes \p c to \p ostream in Hex form. Useful for debugging.
template<typename TextOutputStreamType>
inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const UTF8Character& c)
{
for(const char* p = c.buffer; p != c.buffer + c.length; ++p)
{
ostream << HexChar(*p);
}
return ostream;
}
/// \brief The character-set encoding for the current C locale.
///
/// Obtain the global instance with globalCharacterSet().
class CharacterSet
{
const char* m_charSet;
public:
CharacterSet()
{
if(g_get_charset(&m_charSet) != FALSE)
{
m_charSet = 0;
}
}
bool isUTF8() const
{
return m_charSet == 0;
}
const char* get() const
{
return m_charSet;
}
};
typedef LazyStatic<CharacterSet> GlobalCharacterSet;
/// \brief Returns the global instance of CharacterSet.
inline CharacterSet& globalCharacterSet()
{
return GlobalCharacterSet::instance();
}
class UTF8CharacterToExtendedASCII
{
public:
UTF8Character m_utf8;
char m_c;
UTF8CharacterToExtendedASCII() : m_c('\0')
{
}
UTF8CharacterToExtendedASCII(const UTF8Character& utf8, char c) : m_utf8(utf8), m_c(c)
{
}
};
inline bool operator<(const UTF8CharacterToExtendedASCII& self, const UTF8CharacterToExtendedASCII& other)
{
return self.m_utf8 < other.m_utf8;
}
inline std::size_t extended_ascii_to_index(char c)
{
return static_cast<std::size_t>(c & 0x7F);
}
inline char extended_ascii_for_index(std::size_t i)
{
return static_cast<char>(i | 0x80);
}
/// \brief The active extended-ascii character set encoding.
/// Performs UTF-8 encoding and decoding of extended-ascii characters.
///
/// Obtain the global instance with globalExtendedASCIICharacterSet().
class ExtendedASCIICharacterSet
{
typedef char UTF8CharBuffer[6];
UTF8CharBuffer m_converted[128];
UTF8Character m_decodeMap[128];
UTF8CharacterToExtendedASCII m_encodeMap[128];
public:
ExtendedASCIICharacterSet()
{
if(!globalCharacterSet().isUTF8())
{
GIConv descriptor = g_iconv_open("UTF-8", globalCharacterSet().get());
for(std::size_t i = 1; i < 128; ++i)
{
char c = extended_ascii_for_index(i);
char* inbuf = &c;
std::size_t inbytesleft = 1;
char* outbuf = m_converted[i];
std::size_t outbytesleft = 6;
if(g_iconv(descriptor, &inbuf, &inbytesleft, &outbuf, &outbytesleft) != (size_t)(-1))
{
UTF8Character utf8(m_converted[i]);
m_decodeMap[i] = utf8;
m_encodeMap[i] = UTF8CharacterToExtendedASCII(utf8, c);
}
}
g_iconv_close(descriptor);
std::sort(m_encodeMap, m_encodeMap + 128);
}
}
/// \brief Prints the (up to) 128 characters in the current extended-ascii character set.
/// Useful for debugging.
void print() const
{
globalOutputStream() << "UTF-8 conversion required from charset: " << globalCharacterSet().get() << "\n";
for(std::size_t i = 1; i < 128; ++i)
{
if(m_decodeMap[i].buffer != 0)
{
globalOutputStream() << extended_ascii_for_index(i) << " = " << m_decodeMap[i] << "\n";
}
}
}
/// \brief Returns \p c decoded from extended-ascii to UTF-8.
/// \p c must be an extended-ascii character.
const UTF8Character& decode(char c) const
{
ASSERT_MESSAGE(!globalCharacterSet().isUTF8(), "locale is utf8, no conversion required");
ASSERT_MESSAGE(!char_is_ascii(c), "decode: ascii character");
ASSERT_MESSAGE(m_decodeMap[extended_ascii_to_index(c)].buffer != 0, "decode: invalid character: " << HexChar(c));
return m_decodeMap[extended_ascii_to_index(c)];
}
/// \brief Returns \p c encoded to extended-ascii from UTF-8.
/// \p c must map to an extended-ascii character.
char encode(const UTF8Character& c) const
{
ASSERT_MESSAGE(!globalCharacterSet().isUTF8(), "locale is utf8, no conversion required");
ASSERT_MESSAGE(!char_is_ascii(*c.buffer), "encode: ascii character");
std::pair<const UTF8CharacterToExtendedASCII*, const UTF8CharacterToExtendedASCII*> range
= std::equal_range(m_encodeMap, m_encodeMap + 128, UTF8CharacterToExtendedASCII(c, 0));
ASSERT_MESSAGE(range.first != range.second, "encode: invalid character: " << c);
return (*range.first).m_c;
}
};
typedef LazyStatic<ExtendedASCIICharacterSet> GlobalExtendedASCIICharacterSet;
/// \brief Returns the global instance of ExtendedASCIICharacterSet.
inline ExtendedASCIICharacterSet& globalExtendedASCIICharacterSet()
{
return GlobalExtendedASCIICharacterSet::instance();
}
class ConvertUTF8ToLocale
{
public:
StringRange m_range;
ConvertUTF8ToLocale(const char* string) : m_range(StringRange(string, string + strlen(string)))
{
}
ConvertUTF8ToLocale(const StringRange& range) : m_range(range)
{
}
};
/// \brief Writes \p convert to \p ostream after encoding each character to extended-ascii from UTF-8.
template<typename TextOutputStreamType>
inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const ConvertUTF8ToLocale& convert)
{
if(globalCharacterSet().isUTF8())
{
return ostream << convert.m_range;
}
for(const char* p = convert.m_range.begin; p != convert.m_range.end;)
{
if(!char_is_ascii(*p))
{
UTF8Character c(p);
ostream << globalExtendedASCIICharacterSet().encode(c);
p += c.length;
}
else
{
ostream << *p++;
}
}
return ostream;
}
class ConvertLocaleToUTF8
{
public:
StringRange m_range;
ConvertLocaleToUTF8(const char* string) : m_range(StringRange(string, string + strlen(string)))
{
}
ConvertLocaleToUTF8(const StringRange& range) : m_range(range)
{
}
};
/// \brief Writes \p convert to \p ostream after decoding each character from extended-ascii to UTF-8.
template<typename TextOutputStreamType>
inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const ConvertLocaleToUTF8& convert)
{
if(globalCharacterSet().isUTF8())
{
return ostream << convert.m_range;
}
for(const char* p = convert.m_range.begin; p != convert.m_range.end; ++p)
{
if(!char_is_ascii(*p))
{
UTF8Character c(globalExtendedASCIICharacterSet().decode(*p));
ostream.write(c.buffer, c.length);
}
else
{
ostream << *p;
}
}
return ostream;
}
#endif

250
tools/urt/libs/ddslib.h Normal file
View File

@ -0,0 +1,250 @@
/* -----------------------------------------------------------------------------
DDS Library
Based on code from Nvidia's DDS example:
http://www.nvidia.com/object/dxtc_decompression_code.html
Copyright (c) 2003 Randy Reddig
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the names of the copyright holders nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------- */
/* marker */
#ifndef DDSLIB_H
#define DDSLIB_H
/* dependencies */
#include <stdio.h>
#include <memory.h>
/* c++ marker */
#ifdef __cplusplus
extern "C"
{
#endif
/* dds definition */
typedef enum
{
DDS_PF_ARGB8888,
DDS_PF_DXT1,
DDS_PF_DXT2,
DDS_PF_DXT3,
DDS_PF_DXT4,
DDS_PF_DXT5,
DDS_PF_UNKNOWN
}
ddsPF_t;
/* 16bpp stuff */
#define DDS_LOW_5 0x001F;
#define DDS_MID_6 0x07E0;
#define DDS_HIGH_5 0xF800;
#define DDS_MID_555 0x03E0;
#define DDS_HI_555 0x7C00;
/* structures */
typedef struct ddsColorKey_s
{
unsigned int colorSpaceLowValue;
unsigned int colorSpaceHighValue;
}
ddsColorKey_t;
typedef struct ddsCaps_s
{
unsigned int caps1;
unsigned int caps2;
unsigned int caps3;
unsigned int caps4;
}
ddsCaps_t;
typedef struct ddsMultiSampleCaps_s
{
unsigned short flipMSTypes;
unsigned short bltMSTypes;
}
ddsMultiSampleCaps_t;
typedef struct ddsPixelFormat_s
{
unsigned int size;
unsigned int flags;
unsigned int fourCC;
union
{
unsigned int rgbBitCount;
unsigned int yuvBitCount;
unsigned int zBufferBitDepth;
unsigned int alphaBitDepth;
unsigned int luminanceBitCount;
unsigned int bumpBitCount;
unsigned int privateFormatBitCount;
};
union
{
unsigned int rBitMask;
unsigned int yBitMask;
unsigned int stencilBitDepth;
unsigned int luminanceBitMask;
unsigned int bumpDuBitMask;
unsigned int operations;
};
union
{
unsigned int gBitMask;
unsigned int uBitMask;
unsigned int zBitMask;
unsigned int bumpDvBitMask;
ddsMultiSampleCaps_t multiSampleCaps;
};
union
{
unsigned int bBitMask;
unsigned int vBitMask;
unsigned int stencilBitMask;
unsigned int bumpLuminanceBitMask;
};
union
{
unsigned int rgbAlphaBitMask;
unsigned int yuvAlphaBitMask;
unsigned int luminanceAlphaBitMask;
unsigned int rgbZBitMask;
unsigned int yuvZBitMask;
};
}
ddsPixelFormat_t;
typedef struct ddsBuffer_s
{
/* magic: 'dds ' */
char magic[ 4 ];
/* directdraw surface */
unsigned int size;
unsigned int flags;
unsigned int height;
unsigned int width;
union
{
int pitch;
unsigned int linearSize;
};
unsigned int backBufferCount;
union
{
unsigned int mipMapCount;
unsigned int refreshRate;
unsigned int srcVBHandle;
};
unsigned int alphaBitDepth;
unsigned int reserved;
void *surface;
union
{
ddsColorKey_t ckDestOverlay;
unsigned int emptyFaceColor;
};
ddsColorKey_t ckDestBlt;
ddsColorKey_t ckSrcOverlay;
ddsColorKey_t ckSrcBlt;
union
{
ddsPixelFormat_t pixelFormat;
unsigned int fvf;
};
ddsCaps_t ddsCaps;
unsigned int textureStage;
/* data (Varying size) */
unsigned char data[ 4 ];
}
ddsBuffer_t;
typedef struct ddsColorBlock_s
{
unsigned short colors[ 2 ];
unsigned char row[ 4 ];
}
ddsColorBlock_t;
typedef struct ddsAlphaBlockExplicit_s
{
unsigned short row[ 4 ];
}
ddsAlphaBlockExplicit_t;
typedef struct ddsAlphaBlock3BitLinear_s
{
unsigned char alpha0;
unsigned char alpha1;
unsigned char stuff[ 6 ];
}
ddsAlphaBlock3BitLinear_t;
typedef struct ddsColor_s
{
unsigned char r, g, b, a;
}
ddsColor_t;
/* public functions */
int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, ddsPF_t *pf );
int DDSDecompress( ddsBuffer_t *dds, unsigned char *pixels );
/* end marker */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,781 @@
/* -----------------------------------------------------------------------------
DDS Library
Based on code from Nvidia's DDS example:
http://www.nvidia.com/object/dxtc_decompression_code.html
Copyright (c) 2003 Randy Reddig
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the names of the copyright holders nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------- */
/* marker */
#define DDSLIB_C
/* dependencies */
#include "ddslib.h"
/* endian tomfoolery */
typedef union
{
float f;
char c[ 4 ];
}
floatSwapUnion;
#ifndef __BIG_ENDIAN__
#ifdef _SGI_SOURCE
#define __BIG_ENDIAN__
#endif
#endif
#ifdef __BIG_ENDIAN__
int DDSBigLong( int src ) { return src; }
short DDSBigShort( short src ) { return src; }
float DDSBigFloat( float src ) { return src; }
int DDSLittleLong( int src )
{
return ((src & 0xFF000000) >> 24) |
((src & 0x00FF0000) >> 8) |
((src & 0x0000FF00) << 8) |
((src & 0x000000FF) << 24);
}
short DDSLittleShort( short src )
{
return ((src & 0xFF00) >> 8) |
((src & 0x00FF) << 8);
}
float DDSLittleFloat( float src )
{
floatSwapUnion in,out;
in.f = src;
out.c[ 0 ] = in.c[ 3 ];
out.c[ 1 ] = in.c[ 2 ];
out.c[ 2 ] = in.c[ 1 ];
out.c[ 3 ] = in.c[ 0 ];
return out.f;
}
#else /*__BIG_ENDIAN__*/
int DDSLittleLong( int src ) { return src; }
short DDSLittleShort( short src ) { return src; }
float DDSLittleFloat( float src ) { return src; }
int DDSBigLong( int src )
{
return ((src & 0xFF000000) >> 24) |
((src & 0x00FF0000) >> 8) |
((src & 0x0000FF00) << 8) |
((src & 0x000000FF) << 24);
}
short DDSBigShort( short src )
{
return ((src & 0xFF00) >> 8) |
((src & 0x00FF) << 8);
}
float DDSBigFloat( float src )
{
floatSwapUnion in,out;
in.f = src;
out.c[ 0 ] = in.c[ 3 ];
out.c[ 1 ] = in.c[ 2 ];
out.c[ 2 ] = in.c[ 1 ];
out.c[ 3 ] = in.c[ 0 ];
return out.f;
}
#endif /*__BIG_ENDIAN__*/
/*
DDSDecodePixelFormat()
determines which pixel format the dds texture is in
*/
static void DDSDecodePixelFormat( ddsBuffer_t *dds, ddsPF_t *pf )
{
unsigned int fourCC;
/* dummy check */
if( dds == NULL || pf == NULL )
return;
/* extract fourCC */
fourCC = dds->pixelFormat.fourCC;
/* test it */
if( fourCC == 0 )
*pf = DDS_PF_ARGB8888;
else if( fourCC == *((unsigned int*) "DXT1") )
*pf = DDS_PF_DXT1;
else if( fourCC == *((unsigned int*) "DXT2") )
*pf = DDS_PF_DXT2;
else if( fourCC == *((unsigned int*) "DXT3") )
*pf = DDS_PF_DXT3;
else if( fourCC == *((unsigned int*) "DXT4") )
*pf = DDS_PF_DXT4;
else if( fourCC == *((unsigned int*) "DXT5") )
*pf = DDS_PF_DXT5;
else
*pf = DDS_PF_UNKNOWN;
}
/*
DDSGetInfo()
extracts relevant info from a dds texture, returns 0 on success
*/
int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, ddsPF_t *pf )
{
/* dummy test */
if( dds == NULL )
return -1;
/* test dds header */
if( *((int*) dds->magic) != *((int*) "DDS ") )
return -1;
if( DDSLittleLong( dds->size ) != 124 )
return -1;
/* extract width and height */
if( width != NULL )
*width = DDSLittleLong( dds->width );
if( height != NULL )
*height = DDSLittleLong( dds->height );
/* get pixel format */
DDSDecodePixelFormat( dds, pf );
/* return ok */
return 0;
}
/*
DDSGetColorBlockColors()
extracts colors from a dds color block
*/
static void DDSGetColorBlockColors( ddsColorBlock_t *block, ddsColor_t colors[ 4 ] )
{
unsigned short word;
/* color 0 */
word = DDSLittleShort( block->colors[ 0 ] );
colors[ 0 ].a = 0xff;
/* extract rgb bits */
colors[ 0 ].b = (unsigned char) word;
colors[ 0 ].b <<= 3;
colors[ 0 ].b |= (colors[ 0 ].b >> 5);
word >>= 5;
colors[ 0 ].g = (unsigned char) word;
colors[ 0 ].g <<= 2;
colors[ 0 ].g |= (colors[ 0 ].g >> 5);
word >>= 6;
colors[ 0 ].r = (unsigned char) word;
colors[ 0 ].r <<= 3;
colors[ 0 ].r |= (colors[ 0 ].r >> 5);
/* same for color 1 */
word = DDSLittleShort( block->colors[ 1 ] );
colors[ 1 ].a = 0xff;
/* extract rgb bits */
colors[ 1 ].b = (unsigned char) word;
colors[ 1 ].b <<= 3;
colors[ 1 ].b |= (colors[ 1 ].b >> 5);
word >>= 5;
colors[ 1 ].g = (unsigned char) word;
colors[ 1 ].g <<= 2;
colors[ 1 ].g |= (colors[ 1 ].g >> 5);
word >>= 6;
colors[ 1 ].r = (unsigned char) word;
colors[ 1 ].r <<= 3;
colors[ 1 ].r |= (colors[ 1 ].r >> 5);
/* use this for all but the super-freak math method */
if( block->colors[ 0 ] > block->colors[ 1 ] )
{
/* four-color block: derive the other two colors.
00 = color 0, 01 = color 1, 10 = color 2, 11 = color 3
these two bit codes correspond to the 2-bit fields
stored in the 64-bit block. */
word = ((unsigned short) colors[ 0 ].r * 2 + (unsigned short) colors[ 1 ].r ) / 3;
/* no +1 for rounding */
/* as bits have been shifted to 888 */
colors[ 2 ].r = (unsigned char) word;
word = ((unsigned short) colors[ 0 ].g * 2 + (unsigned short) colors[ 1 ].g) / 3;
colors[ 2 ].g = (unsigned char) word;
word = ((unsigned short) colors[ 0 ].b * 2 + (unsigned short) colors[ 1 ].b) / 3;
colors[ 2 ].b = (unsigned char) word;
colors[ 2 ].a = 0xff;
word = ((unsigned short) colors[ 0 ].r + (unsigned short) colors[ 1 ].r * 2) / 3;
colors[ 3 ].r = (unsigned char) word;
word = ((unsigned short) colors[ 0 ].g + (unsigned short) colors[ 1 ].g * 2) / 3;
colors[ 3 ].g = (unsigned char) word;
word = ((unsigned short) colors[ 0 ].b + (unsigned short) colors[ 1 ].b * 2) / 3;
colors[ 3 ].b = (unsigned char) word;
colors[ 3 ].a = 0xff;
}
else
{
/* three-color block: derive the other color.
00 = color 0, 01 = color 1, 10 = color 2,
11 = transparent.
These two bit codes correspond to the 2-bit fields
stored in the 64-bit block */
word = ((unsigned short) colors[ 0 ].r + (unsigned short) colors[ 1 ].r) / 2;
colors[ 2 ].r = (unsigned char) word;
word = ((unsigned short) colors[ 0 ].g + (unsigned short) colors[ 1 ].g) / 2;
colors[ 2 ].g = (unsigned char) word;
word = ((unsigned short) colors[ 0 ].b + (unsigned short) colors[ 1 ].b) / 2;
colors[ 2 ].b = (unsigned char) word;
colors[ 2 ].a = 0xff;
/* random color to indicate alpha */
colors[ 3 ].r = 0x00;
colors[ 3 ].g = 0xff;
colors[ 3 ].b = 0xff;
colors[ 3 ].a = 0x00;
}
}
/*
DDSDecodeColorBlock()
decodes a dds color block
fixme: make endian-safe
*/
static void DDSDecodeColorBlock( unsigned int *pixel, ddsColorBlock_t *block, int width, unsigned int colors[ 4 ] )
{
int r, n;
unsigned int bits;
unsigned int masks[] = { 3, 12, 3 << 4, 3 << 6 }; /* bit masks = 00000011, 00001100, 00110000, 11000000 */
int shift[] = { 0, 2, 4, 6 };
/* r steps through lines in y */
for( r = 0; r < 4; r++, pixel += (width - 4) ) /* no width * 4 as unsigned int ptr inc will * 4 */
{
/* width * 4 bytes per pixel per line, each j dxtc row is 4 lines of pixels */
/* n steps through pixels */
for( n = 0; n < 4; n++ )
{
bits = block->row[ r ] & masks[ n ];
bits >>= shift[ n ];
switch( bits )
{
case 0:
*pixel = colors[ 0 ];
pixel++;
break;
case 1:
*pixel = colors[ 1 ];
pixel++;
break;
case 2:
*pixel = colors[ 2 ];
pixel++;
break;
case 3:
*pixel = colors[ 3 ];
pixel++;
break;
default:
/* invalid */
pixel++;
break;
}
}
}
}
/*
DDSDecodeAlphaExplicit()
decodes a dds explicit alpha block
*/
static void DDSDecodeAlphaExplicit( unsigned int *pixel, ddsAlphaBlockExplicit_t *alphaBlock, int width, unsigned int alphaZero )
{
int row, pix;
unsigned short word;
ddsColor_t color;
/* clear color */
color.r = 0;
color.g = 0;
color.b = 0;
/* walk rows */
for( row = 0; row < 4; row++, pixel += (width - 4) )
{
word = DDSLittleShort( alphaBlock->row[ row ] );
/* walk pixels */
for( pix = 0; pix < 4; pix++ )
{
/* zero the alpha bits of image pixel */
*pixel &= alphaZero;
color.a = word & 0x000F;
color.a = color.a | (color.a << 4);
*pixel |= *((unsigned int*) &color);
word >>= 4; /* move next bits to lowest 4 */
pixel++; /* move to next pixel in the row */
}
}
}
/*
DDSDecodeAlpha3BitLinear()
decodes interpolated alpha block
*/
static void DDSDecodeAlpha3BitLinear( unsigned int *pixel, ddsAlphaBlock3BitLinear_t *alphaBlock, int width, unsigned int alphaZero )
{
int row, pix;
unsigned int stuff;
unsigned char bits[ 4 ][ 4 ];
unsigned short alphas[ 8 ];
ddsColor_t aColors[ 4 ][ 4 ];
/* get initial alphas */
alphas[ 0 ] = alphaBlock->alpha0;
alphas[ 1 ] = alphaBlock->alpha1;
/* 8-alpha block */
if( alphas[ 0 ] > alphas[ 1 ] )
{
/* 000 = alpha_0, 001 = alpha_1, others are interpolated */
alphas[ 2 ] = ( 6 * alphas[ 0 ] + alphas[ 1 ]) / 7; /* bit code 010 */
alphas[ 3 ] = ( 5 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 7; /* bit code 011 */
alphas[ 4 ] = ( 4 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 7; /* bit code 100 */
alphas[ 5 ] = ( 3 * alphas[ 0 ] + 4 * alphas[ 1 ]) / 7; /* bit code 101 */
alphas[ 6 ] = ( 2 * alphas[ 0 ] + 5 * alphas[ 1 ]) / 7; /* bit code 110 */
alphas[ 7 ] = ( alphas[ 0 ] + 6 * alphas[ 1 ]) / 7; /* bit code 111 */
}
/* 6-alpha block */
else
{
/* 000 = alpha_0, 001 = alpha_1, others are interpolated */
alphas[ 2 ] = (4 * alphas[ 0 ] + alphas[ 1 ]) / 5; /* bit code 010 */
alphas[ 3 ] = (3 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 5; /* bit code 011 */
alphas[ 4 ] = (2 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 5; /* bit code 100 */
alphas[ 5 ] = ( alphas[ 0 ] + 4 * alphas[ 1 ]) / 5; /* bit code 101 */
alphas[ 6 ] = 0; /* bit code 110 */
alphas[ 7 ] = 255; /* bit code 111 */
}
/* decode 3-bit fields into array of 16 bytes with same value */
/* first two rows of 4 pixels each */
stuff = *((unsigned int*) &(alphaBlock->stuff[ 0 ]));
bits[ 0 ][ 0 ] = (unsigned char) (stuff & 0x00000007);
stuff >>= 3;
bits[ 0 ][ 1 ] = (unsigned char) (stuff & 0x00000007);
stuff >>= 3;
bits[ 0 ][ 2 ] = (unsigned char) (stuff & 0x00000007);
stuff >>= 3;
bits[ 0 ][ 3 ] = (unsigned char) (stuff & 0x00000007);
stuff >>= 3;
bits[ 1 ][ 0 ] = (unsigned char) (stuff & 0x00000007);
stuff >>= 3;
bits[ 1 ][ 1 ] = (unsigned char) (stuff & 0x00000007);
stuff >>= 3;
bits[ 1 ][ 2 ] = (unsigned char) (stuff & 0x00000007);
stuff >>= 3;
bits[ 1 ][ 3 ] = (unsigned char) (stuff & 0x00000007);
/* last two rows */
stuff = *((unsigned int*) &(alphaBlock->stuff[ 3 ])); /* last 3 bytes */
bits[ 2 ][ 0 ] = (unsigned char) (stuff & 0x00000007);
stuff >>= 3;
bits[ 2 ][ 1 ] = (unsigned char) (stuff & 0x00000007);
stuff >>= 3;
bits[ 2 ][ 2 ] = (unsigned char) (stuff & 0x00000007);
stuff >>= 3;
bits[ 2 ][ 3 ] = (unsigned char) (stuff & 0x00000007);
stuff >>= 3;
bits[ 3 ][ 0 ] = (unsigned char) (stuff & 0x00000007);
stuff >>= 3;
bits[ 3 ][ 1 ] = (unsigned char) (stuff & 0x00000007);
stuff >>= 3;
bits[ 3 ][ 2 ] = (unsigned char) (stuff & 0x00000007);
stuff >>= 3;
bits[ 3 ][ 3 ] = (unsigned char) (stuff & 0x00000007);
/* decode the codes into alpha values */
for( row = 0; row < 4; row++ )
{
for( pix=0; pix < 4; pix++ )
{
aColors[ row ][ pix ].r = 0;
aColors[ row ][ pix ].g = 0;
aColors[ row ][ pix ].b = 0;
aColors[ row ][ pix ].a = (unsigned char) alphas[ bits[ row ][ pix ] ];
}
}
/* write out alpha values to the image bits */
for( row = 0; row < 4; row++, pixel += width-4 )
{
for( pix = 0; pix < 4; pix++ )
{
/* zero the alpha bits of image pixel */
*pixel &= alphaZero;
/* or the bits into the prev. nulled alpha */
*pixel |= *((unsigned int*) &(aColors[ row ][ pix ]));
pixel++;
}
}
}
/*
DDSDecompressDXT1()
decompresses a dxt1 format texture
*/
static int DDSDecompressDXT1( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )
{
int x, y, xBlocks, yBlocks;
unsigned int *pixel;
ddsColorBlock_t *block;
ddsColor_t colors[ 4 ];
/* setup */
xBlocks = width / 4;
yBlocks = height / 4;
/* walk y */
for( y = 0; y < yBlocks; y++ )
{
/* 8 bytes per block */
block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 8);
/* walk x */
for( x = 0; x < xBlocks; x++, block++ )
{
DDSGetColorBlockColors( block, colors );
pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4);
DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors );
}
}
/* return ok */
return 0;
}
/*
DDSDecompressDXT3()
decompresses a dxt3 format texture
*/
static int DDSDecompressDXT3( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )
{
int x, y, xBlocks, yBlocks;
unsigned int *pixel, alphaZero;
ddsColorBlock_t *block;
ddsAlphaBlockExplicit_t *alphaBlock;
ddsColor_t colors[ 4 ];
/* setup */
xBlocks = width / 4;
yBlocks = height / 4;
/* create zero alpha */
colors[ 0 ].a = 0;
colors[ 0 ].r = 0xFF;
colors[ 0 ].g = 0xFF;
colors[ 0 ].b = 0xFF;
alphaZero = *((unsigned int*) &colors[ 0 ]);
/* walk y */
for( y = 0; y < yBlocks; y++ )
{
/* 8 bytes per block, 1 block for alpha, 1 block for color */
block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 16);
/* walk x */
for( x = 0; x < xBlocks; x++, block++ )
{
/* get alpha block */
alphaBlock = (ddsAlphaBlockExplicit_t*) block;
/* get color block */
block++;
DDSGetColorBlockColors( block, colors );
/* decode color block */
pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4);
DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors );
/* overwrite alpha bits with alpha block */
DDSDecodeAlphaExplicit( pixel, alphaBlock, width, alphaZero );
}
}
/* return ok */
return 0;
}
/*
DDSDecompressDXT5()
decompresses a dxt5 format texture
*/
static int DDSDecompressDXT5( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )
{
int x, y, xBlocks, yBlocks;
unsigned int *pixel, alphaZero;
ddsColorBlock_t *block;
ddsAlphaBlock3BitLinear_t *alphaBlock;
ddsColor_t colors[ 4 ];
/* setup */
xBlocks = width / 4;
yBlocks = height / 4;
/* create zero alpha */
colors[ 0 ].a = 0;
colors[ 0 ].r = 0xFF;
colors[ 0 ].g = 0xFF;
colors[ 0 ].b = 0xFF;
alphaZero = *((unsigned int*) &colors[ 0 ]);
/* walk y */
for( y = 0; y < yBlocks; y++ )
{
/* 8 bytes per block, 1 block for alpha, 1 block for color */
block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 16);
/* walk x */
for( x = 0; x < xBlocks; x++, block++ )
{
/* get alpha block */
alphaBlock = (ddsAlphaBlock3BitLinear_t*) block;
/* get color block */
block++;
DDSGetColorBlockColors( block, colors );
/* decode color block */
pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4);
DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors );
/* overwrite alpha bits with alpha block */
DDSDecodeAlpha3BitLinear( pixel, alphaBlock, width, alphaZero );
}
}
/* return ok */
return 0;
}
/*
DDSDecompressDXT2()
decompresses a dxt2 format texture (fixme: un-premultiply alpha)
*/
static int DDSDecompressDXT2( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )
{
int r;
/* decompress dxt3 first */
r = DDSDecompressDXT3( dds, width, height, pixels );
/* return to sender */
return r;
}
/*
DDSDecompressDXT4()
decompresses a dxt4 format texture (fixme: un-premultiply alpha)
*/
static int DDSDecompressDXT4( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )
{
int r;
/* decompress dxt5 first */
r = DDSDecompressDXT5( dds, width, height, pixels );
/* return to sender */
return r;
}
/*
DDSDecompressARGB8888()
decompresses an argb 8888 format texture
*/
static int DDSDecompressARGB8888( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )
{
int x, y;
unsigned char *in, *out;
/* setup */
in = dds->data;
out = pixels;
/* walk y */
for( y = 0; y < height; y++ )
{
/* walk x */
for( x = 0; x < width; x++ )
{
*out++ = *in++;
*out++ = *in++;
*out++ = *in++;
*out++ = *in++;
}
}
/* return ok */
return 0;
}
/*
DDSDecompress()
decompresses a dds texture into an rgba image buffer, returns 0 on success
*/
int DDSDecompress( ddsBuffer_t *dds, unsigned char *pixels )
{
int width, height, r;
ddsPF_t pf;
/* get dds info */
r = DDSGetInfo( dds, &width, &height, &pf );
if( r )
return r;
/* decompress */
switch( pf )
{
case DDS_PF_ARGB8888:
/* fixme: support other [a]rgb formats */
r = DDSDecompressARGB8888( dds, width, height, pixels );
break;
case DDS_PF_DXT1:
r = DDSDecompressDXT1( dds, width, height, pixels );
break;
case DDS_PF_DXT2:
r = DDSDecompressDXT2( dds, width, height, pixels );
break;
case DDS_PF_DXT3:
r = DDSDecompressDXT3( dds, width, height, pixels );
break;
case DDS_PF_DXT4:
r = DDSDecompressDXT4( dds, width, height, pixels );
break;
case DDS_PF_DXT5:
r = DDSDecompressDXT5( dds, width, height, pixels );
break;
default:
case DDS_PF_UNKNOWN:
memset( pixels, 0xFF, width * height * 4 );
r = -1;
break;
}
/* return to sender */
return r;
}

View File

@ -0,0 +1,106 @@
# Microsoft Developer Studio Project File - Name="ddslib" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=ddslib - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "ddslib.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "ddslib.mak" CFG="ddslib - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "ddslib - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "ddslib - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "Perforce Project"
# PROP Scc_LocalPath ".."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "ddslib - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
F90=df.exe
MTL=midl.exe
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FR /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "ddslib - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
F90=df.exe
MTL=midl.exe
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "ddslib - Win32 Release"
# Name "ddslib - Win32 Debug"
# Begin Group "src"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\ddslib.c
# End Source File
# End Group
# Begin Group "include"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=..\ddslib.h
# End Source File
# End Group
# End Target
# End Project

View File

@ -0,0 +1,27 @@
<html>
<body>
<pre>
<h1>Build Log</h1>
<h3>
--------------------Configuration: ddslib - Win32 Debug--------------------
</h3>
<h3>Command Lines</h3>
Creating temporary file "C:\DOCUME~1\TWENTY~1\LOCALS~1\Temp\RSP5F1.tmp" with contents
[
/nologo /MDd /W3 /Gm /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR"Debug/" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c
"C:\Program Files\Subversion\GtkRadiant\libs\ddslib\ddslib.c"
]
Creating command line "cl.exe @C:\DOCUME~1\TWENTY~1\LOCALS~1\Temp\RSP5F1.tmp"
Creating command line "link.exe -lib /nologo /out:"Debug\ddslib.lib" ".\Debug\ddslib.obj" "
<h3>Output Window</h3>
Compiling...
ddslib.c
Creating library...
<h3>Results</h3>
ddslib.lib - 0 error(s), 0 warning(s)
</pre>
</body>
</html>

View File

@ -0,0 +1,211 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="ddslib"
ProjectGUID="{7FD1FB6D-9969-43E1-857D-1B70B85DB89D}"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Release|Win32"
OutputDirectory=".\Release"
IntermediateDirectory=".\Release"
ConfigurationType="4"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories=".."
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
StringPooling="true"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
PrecompiledHeaderFile=".\Release/ddslib.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile=".\Release\ddslib.lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\Release/ddslib.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|Win32"
OutputDirectory=".\Debug"
IntermediateDirectory=".\Debug"
ConfigurationType="4"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=".."
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
PrecompiledHeaderFile=".\Debug/ddslib.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile=".\Debug\ddslib.lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\Debug/ddslib.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="src"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
>
<File
RelativePath="ddslib.c"
>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="include"
Filter="h;hpp;hxx;hm;inl"
>
<File
RelativePath="..\ddslib.h"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,8 @@
#include "debugging.h"
void TEST_ASSERT()
{
ERROR_MESSAGE("test");
ASSERT_NOTNULL(0);
}

View File

@ -0,0 +1,115 @@
#if !defined(INCLUDED_DEBUGGING_DEBUGGING_H)
#define INCLUDED_DEBUGGING_DEBUGGING_H
/// \file
/// \brief Debugging macros for fatal error/assert messages.
#include "stream/textstream.h"
#include "warnings.h"
#include "generic/static.h"
#if defined(_MSC_VER) && defined(_M_IX86)
#define DEBUGGER_BREAKPOINT() __asm { int 3 }
#elif defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2
#define DEBUGGER_BREAKPOINT() __asm__ __volatile__ ("int $03")
#else
#include <signal.h>
#define DEBUGGER_BREAKPOINT() raise(SIGTRAP);
#endif
#define FILE_LINE __FILE__ ":" << __LINE__
#if defined(_DEBUG) || 1
#define DEBUG_ASSERTS
#endif
class DebugMessageHandler
{
public:
virtual TextOutputStream& getOutputStream() = 0;
virtual bool handleMessage() = 0;
};
class NullDebugMessageHandler : public NullOutputStream, public DebugMessageHandler
{
public:
virtual TextOutputStream& getOutputStream()
{
return *this;
}
virtual bool handleMessage()
{
return false;
}
};
class DefaultDebugMessageHandler : public DebugMessageHandler
{
public:
virtual TextOutputStream& getOutputStream()
{
return globalErrorStream();
}
virtual bool handleMessage()
{
#if defined(_DEBUG)
return false; // send debug-break
#else
return true;
#endif
}
};
class DebugMessageHandlerRef : public DefaultDebugMessageHandler
{
DebugMessageHandler* m_handler;
public:
DebugMessageHandlerRef()
: m_handler(this)
{
}
void setHandler(DebugMessageHandler& handler)
{
m_handler = &handler;
}
DebugMessageHandler& getHandler()
{
return *m_handler;
}
};
typedef Static<DebugMessageHandlerRef> GlobalDebugMessageHandler;
inline DebugMessageHandler& globalDebugMessageHandler()
{
return GlobalDebugMessageHandler::instance().getHandler();
}
#if defined(DEBUG_ASSERTS)
/// \brief Sends a \p message to the current debug-message-handler text-output-stream if \p condition evaluates to false.
#define ASSERT_MESSAGE(condition, message)\
if(!(condition))\
{\
globalDebugMessageHandler().getOutputStream() << FILE_LINE << "\nassertion failure: " << message << "\n";\
if(!globalDebugMessageHandler().handleMessage()) { DEBUGGER_BREAKPOINT(); }\
} else\
/// \brief Sends a \p message to the current debug-message-handler text-output-stream.
#define ERROR_MESSAGE(message)\
globalDebugMessageHandler().getOutputStream() << FILE_LINE << "\nruntime error: " << message << "\n";\
if(!globalDebugMessageHandler().handleMessage()) { DEBUGGER_BREAKPOINT(); } else\
#define ASSERT_NOTNULL(ptr) ASSERT_MESSAGE(ptr != 0, "pointer \"" #ptr "\" is null")
#else
#define ASSERT_MESSAGE(condition, message)
#define ASSERT_NOTNULL(ptr)
#endif
#endif

View File

@ -0,0 +1,3 @@
#include "dragplanes.h"

233
tools/urt/libs/dragplanes.h Normal file
View File

@ -0,0 +1,233 @@
#if !defined(INCLUDED_DRAGPLANES_H)
#define INCLUDED_DRAGPLANES_H
#include "selectable.h"
#include "selectionlib.h"
#include "math/aabb.h"
#include "math/line.h"
class DragPlanes
{
public:
ObservedSelectable m_selectable_right; // +x
ObservedSelectable m_selectable_left; // -x
ObservedSelectable m_selectable_front; // +y
ObservedSelectable m_selectable_back; // -y
ObservedSelectable m_selectable_top; // +z
ObservedSelectable m_selectable_bottom; // -z
Vector3 m_dragPlanesMin;
Vector3 m_dragPlanesMax;
Vector3 m_dragPlanesOrigin;
Vector3 m_dragPlanesExtents;
DragPlanes(const SelectionChangeCallback& onchanged) :
m_selectable_right(onchanged),
m_selectable_left(onchanged),
m_selectable_front(onchanged),
m_selectable_back(onchanged),
m_selectable_top(onchanged),
m_selectable_bottom(onchanged)
{
}
bool isSelected() const
{
return m_selectable_right.isSelected()
|| m_selectable_left.isSelected()
|| m_selectable_front.isSelected()
|| m_selectable_back.isSelected()
|| m_selectable_top.isSelected()
|| m_selectable_bottom.isSelected();
}
void setSelected(bool selected)
{
m_selectable_right.setSelected(selected);
m_selectable_left.setSelected(selected);
m_selectable_front.setSelected(selected);
m_selectable_back.setSelected(selected);
m_selectable_top.setSelected(selected);
m_selectable_bottom.setSelected(selected);
}
void selectPlanes(const AABB& aabb, Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback)
{
Line line(test.getNear(), test.getFar());
Vector3 corners[8];
aabb_corners(aabb, corners);
Plane3 planes[6];
aabb_planes(aabb, planes);
for(Vector3* i = corners; i != corners + 8; ++i)
{
*i = vector3_subtracted(line_closest_point(line, *i), *i);
}
if(vector3_dot(planes[0].normal(), corners[1]) > 0
&& vector3_dot(planes[0].normal(), corners[2]) > 0
&& vector3_dot(planes[0].normal(), corners[5]) > 0
&& vector3_dot(planes[0].normal(), corners[6]) > 0)
{
Selector_add(selector, m_selectable_right);
selectedPlaneCallback(planes[0]);
//globalOutputStream() << "right\n";
}
if(vector3_dot(planes[1].normal(), corners[0]) > 0
&& vector3_dot(planes[1].normal(), corners[3]) > 0
&& vector3_dot(planes[1].normal(), corners[4]) > 0
&& vector3_dot(planes[1].normal(), corners[7]) > 0)
{
Selector_add(selector, m_selectable_left);
selectedPlaneCallback(planes[1]);
//globalOutputStream() << "left\n";
}
if(vector3_dot(planes[2].normal(), corners[0]) > 0
&& vector3_dot(planes[2].normal(), corners[1]) > 0
&& vector3_dot(planes[2].normal(), corners[4]) > 0
&& vector3_dot(planes[2].normal(), corners[5]) > 0)
{
Selector_add(selector, m_selectable_front);
selectedPlaneCallback(planes[2]);
//globalOutputStream() << "front\n";
}
if(vector3_dot(planes[3].normal(), corners[2]) > 0
&& vector3_dot(planes[3].normal(), corners[3]) > 0
&& vector3_dot(planes[3].normal(), corners[6]) > 0
&& vector3_dot(planes[3].normal(), corners[7]) > 0)
{
Selector_add(selector, m_selectable_back);
selectedPlaneCallback(planes[3]);
//globalOutputStream() << "back\n";
}
if(vector3_dot(planes[4].normal(), corners[0]) > 0
&& vector3_dot(planes[4].normal(), corners[1]) > 0
&& vector3_dot(planes[4].normal(), corners[2]) > 0
&& vector3_dot(planes[4].normal(), corners[3]) > 0)
{
Selector_add(selector, m_selectable_top);
selectedPlaneCallback(planes[4]);
//globalOutputStream() << "top\n";
}
if(vector3_dot(planes[5].normal(), corners[4]) > 0
&& vector3_dot(planes[5].normal(), corners[5]) > 0
&& vector3_dot(planes[5].normal(), corners[6]) > 0
&& vector3_dot(planes[5].normal(), corners[7]) > 0)
{
Selector_add(selector, m_selectable_bottom);
//globalOutputStream() << "bottom\n";
selectedPlaneCallback(planes[5]);
}
m_dragPlanesMin = aabb.origin - aabb.extents;
m_dragPlanesMax = aabb.origin + aabb.extents;
m_dragPlanesOrigin = aabb.origin;
m_dragPlanesExtents = aabb.extents;
}
void selectReversedPlanes(const AABB& aabb, Selector& selector, const SelectedPlanes& selectedPlanes)
{
Plane3 planes[6];
aabb_planes(aabb, planes);
if(selectedPlanes.contains(plane3_flipped(planes[0])))
{
Selector_add(selector, m_selectable_right);
}
if(selectedPlanes.contains(plane3_flipped(planes[1])))
{
Selector_add(selector, m_selectable_left);
}
if(selectedPlanes.contains(plane3_flipped(planes[2])))
{
Selector_add(selector, m_selectable_front);
}
if(selectedPlanes.contains(plane3_flipped(planes[3])))
{
Selector_add(selector, m_selectable_back);
}
if(selectedPlanes.contains(plane3_flipped(planes[4])))
{
Selector_add(selector, m_selectable_top);
}
if(selectedPlanes.contains(plane3_flipped(planes[5])))
{
Selector_add(selector, m_selectable_bottom);
}
}
void translate(const Vector3& translation)
{
if(m_dragPlanesExtents[0] != 0)
{
if(m_selectable_right.isSelected())
{
m_dragPlanesMax[0] += translation[0];
//globalOutputStream() << "moving right\n";
}
if(m_selectable_left.isSelected())
{
m_dragPlanesMin[0] += translation[0];
//globalOutputStream() << "moving left\n";
}
}
if(m_dragPlanesExtents[1] != 0)
{
if(m_selectable_front.isSelected())
{
m_dragPlanesMax[1] += translation[1];
//globalOutputStream() << "moving front\n";
}
if(m_selectable_back.isSelected())
{
m_dragPlanesMin[1] += translation[1];
//globalOutputStream() << "moving back\n";
}
}
if(m_dragPlanesExtents[2] != 0)
{
if(m_selectable_top.isSelected())
{
m_dragPlanesMax[2] += translation[2];
//globalOutputStream() << "moving top\n";
}
if(m_selectable_bottom.isSelected())
{
m_dragPlanesMin[2] += translation[2];
//globalOutputStream() << "moving bottom\n";
}
}
}
Matrix4 evaluateTransform() const
{
Vector3 originTransformed(vector3_mid(m_dragPlanesMin, m_dragPlanesMax));
Vector3 scale(vector3_scaled(vector3_subtracted(m_dragPlanesMax, m_dragPlanesMin), 0.5));
if(m_dragPlanesExtents[0] != 0)
{
scale[0] /= m_dragPlanesExtents[0];
}
else
{
scale[0] = 1;
}
if(m_dragPlanesExtents[1] != 0)
{
scale[1] /= m_dragPlanesExtents[1];
}
else
{
scale[1] = 1;
}
if(m_dragPlanesExtents[2] != 0)
{
scale[2] /= m_dragPlanesExtents[2];
}
else
{
scale[2] = 1;
}
Matrix4 matrix(matrix4_translation_for_vec3(originTransformed - m_dragPlanesOrigin));
matrix4_pivoted_scale_by_vec3(matrix, scale, m_dragPlanesOrigin);
return matrix;
}
};
#endif

View File

@ -0,0 +1,2 @@
#include "eclasslib.h"

321
tools/urt/libs/eclasslib.h Normal file
View File

@ -0,0 +1,321 @@
#if !defined (INCLUDED_ECLASSLIB_H)
#define INCLUDED_ECLASSLIB_H
#include <stdio.h>
#include <stdlib.h>
#include <list>
#include <map>
#include <vector>
#include "ieclass.h"
#include "irender.h"
#include "math/vector.h"
#include "string/string.h"
typedef Vector3 Colour3;
class ListAttributeType
{
typedef std::pair<CopiedString, CopiedString> ListItem;
typedef std::vector<ListItem> ListItems;
ListItems m_items;
public:
typedef ListItems::const_iterator const_iterator;
const_iterator begin() const
{
return m_items.begin();
}
const_iterator end() const
{
return m_items.end();
}
const ListItem& operator[](std::size_t i) const
{
return m_items[i];
}
const_iterator findValue(const char* value) const
{
for(ListItems::const_iterator i = m_items.begin(); i != m_items.end(); ++i)
{
if(string_equal(value, (*i).second.c_str()))
{
return i;
}
}
return m_items.end();
}
void push_back(const char* name, const char* value)
{
m_items.push_back(ListItems::value_type(name, value));
}
};
class EntityClassAttribute
{
public:
CopiedString m_type;
CopiedString m_name;
CopiedString m_value;
CopiedString m_description;
EntityClassAttribute()
{
}
EntityClassAttribute(const char* type, const char* name, const char* value = "", const char* description = "") : m_type(type), m_name(name), m_value(value), m_description(description)
{
}
};
typedef std::pair<CopiedString, EntityClassAttribute> EntityClassAttributePair;
typedef std::list<EntityClassAttributePair> EntityClassAttributes;
typedef std::list<CopiedString> StringList;
inline const char* EntityClassAttributePair_getName(const EntityClassAttributePair& attributePair)
{
if(!string_empty(attributePair.second.m_name.c_str()))
{
return attributePair.second.m_name.c_str();
}
return attributePair.first.c_str();
}
inline const char* EntityClassAttributePair_getDescription(const EntityClassAttributePair& attributePair)
{
if(!string_empty(attributePair.second.m_description.c_str()))
{
return attributePair.second.m_description.c_str();
}
return EntityClassAttributePair_getName(attributePair);
}
class EntityClass
{
public:
CopiedString m_name;
StringList m_parent;
bool fixedsize;
bool unknown; // wasn't found in source
Vector3 mins;
Vector3 maxs;
Colour3 color;
Shader* m_state_fill;
Shader* m_state_wire;
Shader* m_state_blend;
CopiedString m_comments;
char flagnames[MAX_FLAGS][32];
CopiedString m_modelpath;
CopiedString m_skin;
void (*free)(EntityClass*);
EntityClassAttributes m_attributes;
bool inheritanceResolved;
bool sizeSpecified;
bool colorSpecified;
const char* name() const
{
return m_name.c_str();
}
const char* comments() const
{
return m_comments.c_str();
}
const char* modelpath() const
{
return m_modelpath.c_str();
}
const char* skin() const
{
return m_skin.c_str();
}
};
inline const char* EntityClass_valueForKey(const EntityClass& entityClass, const char* key)
{
for(EntityClassAttributes::const_iterator i = entityClass.m_attributes.begin(); i != entityClass.m_attributes.end(); ++i)
{
if(string_equal(key, (*i).first.c_str()))
{
return (*i).second.m_value.c_str();
}
}
return "";
}
inline EntityClassAttributePair& EntityClass_insertAttribute(EntityClass& entityClass, const char* key, const EntityClassAttribute& attribute = EntityClassAttribute())
{
entityClass.m_attributes.push_back(EntityClassAttributePair(key, attribute));
return entityClass.m_attributes.back();
}
inline void buffer_write_colour_fill(char buffer[128], const Colour3& colour)
{
sprintf(buffer, "(%g %g %g)", colour[0], colour[1], colour[2]);
}
inline void buffer_write_colour_wire(char buffer[128], const Colour3& colour)
{
sprintf(buffer, "<%g %g %g>", colour[0], colour[1], colour[2]);
}
inline void buffer_write_colour_blend(char buffer[128], const Colour3& colour)
{
sprintf(buffer, "[%g %g %g]", colour[0], colour[1], colour[2]);
}
inline Shader* colour_capture_state_fill(const Colour3& colour)
{
char buffer[128];
buffer_write_colour_fill(buffer, colour);
return GlobalShaderCache().capture(buffer);
}
inline void colour_release_state_fill(const Colour3& colour)
{
char buffer[128];
buffer_write_colour_fill(buffer, colour);
GlobalShaderCache().release(buffer);
}
inline Shader* colour_capture_state_wire(const Colour3& colour)
{
char buffer[128];
buffer_write_colour_wire(buffer, colour);
return GlobalShaderCache().capture(buffer);
}
inline void colour_release_state_wire(const Colour3& colour)
{
char buffer[128];
buffer_write_colour_wire(buffer, colour);
GlobalShaderCache().release(buffer);
}
inline Shader* colour_capture_state_blend(const Colour3& colour)
{
char buffer[128];
buffer_write_colour_blend(buffer, colour);
return GlobalShaderCache().capture(buffer);
}
inline void colour_release_state_blend(const Colour3& colour)
{
char buffer[128];
buffer_write_colour_blend(buffer, colour);
GlobalShaderCache().release(buffer);
}
inline void eclass_capture_state(EntityClass* eclass)
{
eclass->m_state_fill = colour_capture_state_fill(eclass->color);
eclass->m_state_wire = colour_capture_state_wire(eclass->color);
eclass->m_state_blend = colour_capture_state_blend(eclass->color);
}
inline void eclass_release_state(EntityClass* eclass)
{
colour_release_state_fill(eclass->color);
colour_release_state_wire(eclass->color);
colour_release_state_blend(eclass->color);
}
// eclass constructor
inline EntityClass* Eclass_Alloc()
{
EntityClass* e = new EntityClass;
e->fixedsize = false;
e->unknown = false;
memset(e->flagnames, 0, MAX_FLAGS*32);
e->maxs = Vector3(-1,-1,-1);
e->mins = Vector3(1, 1, 1);
e->free = 0;
e->inheritanceResolved = true;
e->sizeSpecified = false;
e->colorSpecified = false;
return e;
}
// eclass destructor
inline void Eclass_Free(EntityClass* e)
{
eclass_release_state(e);
delete e;
}
inline bool classname_equal(const char* classname, const char* other)
{
return string_equal(classname, other);
}
inline EntityClass* EClass_Create(const char* name, const Vector3& colour, const char* comments)
{
EntityClass *e = Eclass_Alloc();
e->free = &Eclass_Free;
e->m_name = name;
e->color = colour;
eclass_capture_state(e);
if (comments)
e->m_comments = comments;
return e;
}
inline EntityClass* EClass_Create_FixedSize(const char* name, const Vector3& colour, const Vector3& mins, const Vector3& maxs, const char* comments)
{
EntityClass *e = Eclass_Alloc();
e->free = &Eclass_Free;
e->m_name = name;
e->color = colour;
eclass_capture_state(e);
e->fixedsize = true;
e->mins = mins;
e->maxs = maxs;
if (comments)
e->m_comments = comments;
return e;
}
const Vector3 smallbox[2] = {
Vector3(-8,-8,-8),
Vector3( 8, 8, 8),
};
inline EntityClass *EntityClass_Create_Default(const char *name, bool has_brushes)
{
// create a new class for it
if (has_brushes)
{
return EClass_Create(name, Vector3(0.0f, 0.5f, 0.0f), "Not found in source.");
}
else
{
return EClass_Create_FixedSize(name, Vector3(0.0f, 0.5f, 0.0f), smallbox[0], smallbox[1], "Not found in source.");
}
}
#endif

View File

@ -0,0 +1,2 @@
#include "entitylib.h"

726
tools/urt/libs/entitylib.h Normal file
View File

@ -0,0 +1,726 @@
#if !defined (INCLUDED_ENTITYLIB_H)
#define INCLUDED_ENTITYLIB_H
#include "ireference.h"
#include "debugging/debugging.h"
#include "ientity.h"
#include "irender.h"
#include "igl.h"
#include "selectable.h"
#include "generic/callback.h"
#include "math/vector.h"
#include "math/aabb.h"
#include "undolib.h"
#include "string/string.h"
#include "generic/referencecounted.h"
#include "scenelib.h"
#include "container/container.h"
#include "eclasslib.h"
#include <list>
#include <set>
inline void arrow_draw(const Vector3& origin, const Vector3& direction)
{
Vector3 up(0, 0, 1);
Vector3 left(-direction[1], direction[0], 0);
Vector3 endpoint(vector3_added(origin, vector3_scaled(direction, 32.0)));
Vector3 tip1(vector3_added(vector3_added(endpoint, vector3_scaled(direction, -8.0)), vector3_scaled(up, -4.0)));
Vector3 tip2(vector3_added(tip1, vector3_scaled(up, 8.0)));
Vector3 tip3(vector3_added(vector3_added(endpoint, vector3_scaled(direction, -8.0)), vector3_scaled(left, -4.0)));
Vector3 tip4(vector3_added(tip3, vector3_scaled(left, 8.0)));
glBegin (GL_LINES);
glVertex3fv(vector3_to_array(origin));
glVertex3fv(vector3_to_array(endpoint));
glVertex3fv(vector3_to_array(endpoint));
glVertex3fv(vector3_to_array(tip1));
glVertex3fv(vector3_to_array(endpoint));
glVertex3fv(vector3_to_array(tip2));
glVertex3fv(vector3_to_array(endpoint));
glVertex3fv(vector3_to_array(tip3));
glVertex3fv(vector3_to_array(endpoint));
glVertex3fv(vector3_to_array(tip4));
glVertex3fv(vector3_to_array(tip1));
glVertex3fv(vector3_to_array(tip3));
glVertex3fv(vector3_to_array(tip3));
glVertex3fv(vector3_to_array(tip2));
glVertex3fv(vector3_to_array(tip2));
glVertex3fv(vector3_to_array(tip4));
glVertex3fv(vector3_to_array(tip4));
glVertex3fv(vector3_to_array(tip1));
glEnd();
}
class SelectionIntersection;
inline void aabb_testselect(const AABB& aabb, SelectionTest& test, SelectionIntersection& best)
{
const IndexPointer::index_type indices[24] = {
2, 1, 5, 6,
1, 0, 4, 5,
0, 1, 2, 3,
3, 7, 4, 0,
3, 2, 6, 7,
7, 6, 5, 4,
};
Vector3 points[8];
aabb_corners(aabb, points);
test.TestQuads(VertexPointer(reinterpret_cast<VertexPointer::pointer>(points), sizeof(Vector3)), IndexPointer(indices, 24), best);
}
inline void aabb_draw_wire(const Vector3 points[8])
{
typedef std::size_t index_t;
index_t indices[24] = {
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 4, 1, 5, 2, 6, 3, 7,
};
#if 1
glVertexPointer(3, GL_FLOAT, 0, points);
glDrawElements(GL_LINES, sizeof(indices)/sizeof(index_t), GL_UNSIGNED_INT, indices);
#else
glBegin(GL_LINES);
for(std::size_t i = 0; i < sizeof(indices)/sizeof(index_t); ++i)
{
glVertex3fv(points[indices[i]]);
}
glEnd();
#endif
}
inline void aabb_draw_flatshade(const Vector3 points[8])
{
glBegin(GL_QUADS);
glNormal3fv(vector3_to_array(aabb_normals[0]));
glVertex3fv(vector3_to_array(points[2]));
glVertex3fv(vector3_to_array(points[1]));
glVertex3fv(vector3_to_array(points[5]));
glVertex3fv(vector3_to_array(points[6]));
glNormal3fv(vector3_to_array(aabb_normals[1]));
glVertex3fv(vector3_to_array(points[1]));
glVertex3fv(vector3_to_array(points[0]));
glVertex3fv(vector3_to_array(points[4]));
glVertex3fv(vector3_to_array(points[5]));
glNormal3fv(vector3_to_array(aabb_normals[2]));
glVertex3fv(vector3_to_array(points[0]));
glVertex3fv(vector3_to_array(points[1]));
glVertex3fv(vector3_to_array(points[2]));
glVertex3fv(vector3_to_array(points[3]));
glNormal3fv(vector3_to_array(aabb_normals[3]));
glVertex3fv(vector3_to_array(points[0]));
glVertex3fv(vector3_to_array(points[3]));
glVertex3fv(vector3_to_array(points[7]));
glVertex3fv(vector3_to_array(points[4]));
glNormal3fv(vector3_to_array(aabb_normals[4]));
glVertex3fv(vector3_to_array(points[3]));
glVertex3fv(vector3_to_array(points[2]));
glVertex3fv(vector3_to_array(points[6]));
glVertex3fv(vector3_to_array(points[7]));
glNormal3fv(vector3_to_array(aabb_normals[5]));
glVertex3fv(vector3_to_array(points[7]));
glVertex3fv(vector3_to_array(points[6]));
glVertex3fv(vector3_to_array(points[5]));
glVertex3fv(vector3_to_array(points[4]));
glEnd();
}
inline void aabb_draw_wire(const AABB& aabb)
{
Vector3 points[8];
aabb_corners(aabb, points);
aabb_draw_wire(points);
}
inline void aabb_draw_flatshade(const AABB& aabb)
{
Vector3 points[8];
aabb_corners(aabb, points);
aabb_draw_flatshade(points);
}
inline void aabb_draw_textured(const AABB& aabb)
{
Vector3 points[8];
aabb_corners(aabb, points);
glBegin(GL_QUADS);
glNormal3fv(vector3_to_array(aabb_normals[0]));
glTexCoord2fv(aabb_texcoord_topleft);
glVertex3fv(vector3_to_array(points[2]));
glTexCoord2fv(aabb_texcoord_topright);
glVertex3fv(vector3_to_array(points[1]));
glTexCoord2fv(aabb_texcoord_botright);
glVertex3fv(vector3_to_array(points[5]));
glTexCoord2fv(aabb_texcoord_botleft);
glVertex3fv(vector3_to_array(points[6]));
glNormal3fv(vector3_to_array(aabb_normals[1]));
glTexCoord2fv(aabb_texcoord_topleft);
glVertex3fv(vector3_to_array(points[1]));
glTexCoord2fv(aabb_texcoord_topright);
glVertex3fv(vector3_to_array(points[0]));
glTexCoord2fv(aabb_texcoord_botright);
glVertex3fv(vector3_to_array(points[4]));
glTexCoord2fv(aabb_texcoord_botleft);
glVertex3fv(vector3_to_array(points[5]));
glNormal3fv(vector3_to_array(aabb_normals[2]));
glTexCoord2fv(aabb_texcoord_topleft);
glVertex3fv(vector3_to_array(points[0]));
glTexCoord2fv(aabb_texcoord_topright);
glVertex3fv(vector3_to_array(points[1]));
glTexCoord2fv(aabb_texcoord_botright);
glVertex3fv(vector3_to_array(points[2]));
glTexCoord2fv(aabb_texcoord_botleft);
glVertex3fv(vector3_to_array(points[3]));
glNormal3fv(vector3_to_array(aabb_normals[3]));
glTexCoord2fv(aabb_texcoord_topleft);
glVertex3fv(vector3_to_array(points[0]));
glTexCoord2fv(aabb_texcoord_topright);
glVertex3fv(vector3_to_array(points[3]));
glTexCoord2fv(aabb_texcoord_botright);
glVertex3fv(vector3_to_array(points[7]));
glTexCoord2fv(aabb_texcoord_botleft);
glVertex3fv(vector3_to_array(points[4]));
glNormal3fv(vector3_to_array(aabb_normals[4]));
glTexCoord2fv(aabb_texcoord_topleft);
glVertex3fv(vector3_to_array(points[3]));
glTexCoord2fv(aabb_texcoord_topright);
glVertex3fv(vector3_to_array(points[2]));
glTexCoord2fv(aabb_texcoord_botright);
glVertex3fv(vector3_to_array(points[6]));
glTexCoord2fv(aabb_texcoord_botleft);
glVertex3fv(vector3_to_array(points[7]));
glNormal3fv(vector3_to_array(aabb_normals[5]));
glTexCoord2fv(aabb_texcoord_topleft);
glVertex3fv(vector3_to_array(points[7]));
glTexCoord2fv(aabb_texcoord_topright);
glVertex3fv(vector3_to_array(points[6]));
glTexCoord2fv(aabb_texcoord_botright);
glVertex3fv(vector3_to_array(points[5]));
glTexCoord2fv(aabb_texcoord_botleft);
glVertex3fv(vector3_to_array(points[4]));
glEnd();
}
inline void aabb_draw_solid(const AABB& aabb, RenderStateFlags state)
{
if(state & RENDER_TEXTURE)
{
aabb_draw_textured(aabb);
}
else
{
aabb_draw_flatshade(aabb);
}
}
inline void aabb_draw(const AABB& aabb, RenderStateFlags state)
{
if(state & RENDER_FILL)
{
aabb_draw_solid(aabb, state);
}
else
{
aabb_draw_wire(aabb);
}
}
class RenderableSolidAABB : public OpenGLRenderable
{
const AABB& m_aabb;
public:
RenderableSolidAABB(const AABB& aabb) : m_aabb(aabb)
{
}
void render(RenderStateFlags state) const
{
aabb_draw_solid(m_aabb, state);
}
};
class RenderableWireframeAABB : public OpenGLRenderable
{
const AABB& m_aabb;
public:
RenderableWireframeAABB(const AABB& aabb) : m_aabb(aabb)
{
}
void render(RenderStateFlags state) const
{
aabb_draw_wire(m_aabb);
}
};
typedef Callback1<const char*> KeyObserver;
/// \brief A key/value pair of strings.
///
/// - Notifies observers when value changes - value changes to "" on destruction.
/// - Provides undo support through the global undo system.
class KeyValue
{
typedef UnsortedSet<KeyObserver> KeyObservers;
std::size_t m_refcount;
KeyObservers m_observers;
CopiedString m_string;
const char* m_empty;
ObservedUndoableObject<CopiedString> m_undo;
static EntityCreator::KeyValueChangedFunc m_entityKeyValueChanged;
public:
KeyValue(const char* string, const char* empty)
: m_refcount(0), m_string(string), m_empty(empty), m_undo(m_string, UndoImportCaller(*this))
{
notify();
}
~KeyValue()
{
ASSERT_MESSAGE(m_observers.empty(), "KeyValue::~KeyValue: observers still attached");
}
static void setKeyValueChangedFunc(EntityCreator::KeyValueChangedFunc func)
{
m_entityKeyValueChanged = func;
}
void IncRef()
{
++m_refcount;
}
void DecRef()
{
if(--m_refcount == 0)
{
delete this;
}
}
void instanceAttach(MapFile* map)
{
m_undo.instanceAttach(map);
}
void instanceDetach(MapFile* map)
{
m_undo.instanceDetach(map);
}
void attach(const KeyObserver& observer)
{
(*m_observers.insert(observer))(c_str());
}
void detach(const KeyObserver& observer)
{
observer(m_empty);
m_observers.erase(observer);
}
const char* c_str() const
{
if(string_empty(m_string.c_str()))
{
return m_empty;
}
return m_string.c_str();
}
void assign(const char* other)
{
if(!string_equal(m_string.c_str(), other))
{
m_undo.save();
m_string = other;
notify();
}
}
void notify()
{
m_entityKeyValueChanged();
KeyObservers::reverse_iterator i = m_observers.rbegin();
while(i != m_observers.rend())
{
(*i++)(c_str());
}
}
void importState(const CopiedString& string)
{
m_string = string;
notify();
}
typedef MemberCaller1<KeyValue, const CopiedString&, &KeyValue::importState> UndoImportCaller;
};
/// \brief An unsorted list of key/value pairs.
///
/// - Notifies observers when a pair is inserted or removed.
/// - Provides undo support through the global undo system.
/// - New keys are appended to the end of the list.
class EntityKeyValues : public Entity
{
public:
typedef KeyValue Value;
class Observer
{
public:
virtual void insert(const char* key, Value& value) = 0;
virtual void erase(const char* key, Value& value) = 0;
};
private:
static EntityCreator::KeyValueChangedFunc m_entityKeyValueChanged;
static Counter* m_counter;
EntityClass* m_eclass;
typedef SmartPointer<KeyValue> KeyValuePtr;
typedef UnsortedMap<CopiedString, KeyValuePtr > KeyValues;
KeyValues m_keyValues;
typedef UnsortedSet<Observer*> Observers;
Observers m_observers;
ObservedUndoableObject<KeyValues> m_undo;
bool m_instanced;
bool m_observerMutex;
void notifyInsert(const char* key, Value& value)
{
m_observerMutex = true;
for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i)
{
(*i)->insert(key, value);
}
m_observerMutex = false;
}
void notifyErase(const char* key, Value& value)
{
m_observerMutex = true;
for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i)
{
(*i)->erase(key, value);
}
m_observerMutex = false;
}
void forEachKeyValue_notifyInsert()
{
for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
notifyInsert((*i).first.c_str(), *(*i).second);
}
}
void forEachKeyValue_notifyErase()
{
for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
notifyErase((*i).first.c_str(), *(*i).second);
}
}
void insert(const char* key, const KeyValuePtr& keyValue)
{
KeyValues::iterator i = m_keyValues.insert(KeyValues::value_type(key, keyValue));
notifyInsert(key, *(*i).second);
if(m_instanced)
{
(*i).second->instanceAttach(m_undo.map());
}
}
void insert(const char* key, const char* value)
{
KeyValues::iterator i = m_keyValues.find(key);
if(i != m_keyValues.end())
{
(*i).second->assign(value);
}
else
{
m_undo.save();
insert(key, KeyValuePtr(new KeyValue(value, EntityClass_valueForKey(*m_eclass, key))));
}
}
void erase(KeyValues::iterator i)
{
if(m_instanced)
{
(*i).second->instanceDetach(m_undo.map());
}
CopiedString key((*i).first);
KeyValuePtr value((*i).second);
m_keyValues.erase(i);
notifyErase(key.c_str(), *value);
}
void erase(const char* key)
{
KeyValues::iterator i = m_keyValues.find(key);
if(i != m_keyValues.end())
{
m_undo.save();
erase(i);
}
}
public:
EntityKeyValues(EntityClass* eclass) :
m_eclass(eclass),
m_undo(m_keyValues, UndoImportCaller(*this)),
m_instanced(false),
m_observerMutex(false)
{
}
EntityKeyValues(const EntityKeyValues& other) :
Entity(other),
m_eclass(&other.getEntityClass()),
m_undo(m_keyValues, UndoImportCaller(*this)),
m_instanced(false),
m_observerMutex(false)
{
for(KeyValues::const_iterator i = other.m_keyValues.begin(); i != other.m_keyValues.end(); ++i)
{
insert((*i).first.c_str(), (*i).second->c_str());
}
}
~EntityKeyValues()
{
ASSERT_MESSAGE(m_observers.empty(), "EntityKeyValues::~EntityKeyValues: observers still attached");
}
static void setKeyValueChangedFunc(EntityCreator::KeyValueChangedFunc func)
{
m_entityKeyValueChanged = func;
KeyValue::setKeyValueChangedFunc(func);
}
static void setCounter(Counter* counter)
{
m_counter = counter;
}
void importState(const KeyValues& keyValues)
{
for(KeyValues::iterator i = m_keyValues.begin(); i != m_keyValues.end();)
{
erase(i++);
}
for(KeyValues::const_iterator i = keyValues.begin(); i != keyValues.end(); ++i)
{
insert((*i).first.c_str(), (*i).second);
}
m_entityKeyValueChanged();
}
typedef MemberCaller1<EntityKeyValues, const KeyValues&, &EntityKeyValues::importState> UndoImportCaller;
void attach(Observer& observer)
{
ASSERT_MESSAGE(!m_observerMutex, "observer cannot be attached during iteration");
m_observers.insert(&observer);
for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
observer.insert((*i).first.c_str(), *(*i).second);
}
}
void detach(Observer& observer)
{
ASSERT_MESSAGE(!m_observerMutex, "observer cannot be detached during iteration");
m_observers.erase(&observer);
for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
observer.erase((*i).first.c_str(), *(*i).second);
}
}
void forEachKeyValue_instanceAttach(MapFile* map)
{
for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
(*i).second->instanceAttach(map);
}
}
void forEachKeyValue_instanceDetach(MapFile* map)
{
for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
(*i).second->instanceDetach(map);
}
}
void instanceAttach(MapFile* map)
{
if(m_counter != 0)
{
m_counter->increment();
}
m_instanced = true;
forEachKeyValue_instanceAttach(map);
m_undo.instanceAttach(map);
}
void instanceDetach(MapFile* map)
{
if(m_counter != 0)
{
m_counter->decrement();
}
m_undo.instanceDetach(map);
forEachKeyValue_instanceDetach(map);
m_instanced = false;
}
// entity
EntityClass& getEntityClass() const
{
return *m_eclass;
}
void forEachKeyValue(Visitor& visitor) const
{
for(KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
visitor.visit((*i).first.c_str(), (*i).second->c_str());
}
}
void setKeyValue(const char* key, const char* value)
{
if(value[0] == '\0'
/*|| string_equal(EntityClass_valueForKey(*m_eclass, key), value)*/) // don't delete values equal to default
{
erase(key);
}
else
{
insert(key, value);
}
m_entityKeyValueChanged();
}
const char* getKeyValue(const char* key) const
{
KeyValues::const_iterator i = m_keyValues.find(key);
if(i != m_keyValues.end())
{
return (*i).second->c_str();
}
return EntityClass_valueForKey(*m_eclass, key);
}
};
/// \brief A Resource reference with a controlled lifetime.
/// \brief The resource is released when the ResourceReference is destroyed.
class ResourceReference
{
CopiedString m_name;
Resource* m_resource;
public:
ResourceReference(const char* name)
: m_name(name)
{
capture();
}
ResourceReference(const ResourceReference& other)
: m_name(other.m_name)
{
capture();
}
ResourceReference& operator=(const ResourceReference& other)
{
ResourceReference tmp(other);
tmp.swap(*this);
return *this;
}
~ResourceReference()
{
release();
}
void capture()
{
m_resource = GlobalReferenceCache().capture(m_name.c_str());
}
void release()
{
GlobalReferenceCache().release(m_name.c_str());
}
const char* getName() const
{
return m_name.c_str();
}
void setName(const char* name)
{
ResourceReference tmp(name);
tmp.swap(*this);
}
void swap(ResourceReference& other)
{
std::swap(m_resource, other.m_resource);
std::swap(m_name, other.m_name);
}
void attach(ModuleObserver& observer)
{
m_resource->attach(observer);
}
void detach(ModuleObserver& observer)
{
m_resource->detach(observer);
}
Resource* get()
{
return m_resource;
}
};
namespace std
{
/// \brief Swaps the values of \p self and \p other.
/// Overloads std::swap.
inline void swap(ResourceReference& self, ResourceReference& other)
{
self.swap(other);
}
}
#endif

View File

@ -0,0 +1,2 @@
#include "entityxml.h"

View File

@ -0,0 +1,88 @@
#if !defined(INCLUDED_ENTITYXML_H)
#define INCLUDED_ENTITYXML_H
#include "ientity.h"
#include "xml/ixml.h"
#include "xml/xmlelement.h"
class entity_import : public XMLImporter
{
Entity& m_entity;
public:
entity_import(Entity& entity)
: m_entity(entity)
{
}
void pushElement(const XMLElement& element)
{
if(strcmp(element.name(), "epair") == 0)
m_entity.setKeyValue(element.attribute("key"), element.attribute("value"));
}
void popElement(const char* name)
{
}
std::size_t write(const char* data, std::size_t length)
{
return length;
}
};
class entity_export : public XMLExporter
{
class ExportXMLVisitor : public Entity::Visitor
{
XMLImporter& m_importer;
public:
ExportXMLVisitor(XMLImporter& importer) : m_importer(importer)
{
}
void visit(const char* key, const char* value)
{
StaticElement element("epair");
element.insertAttribute("key", key);
element.insertAttribute("value", value);
m_importer.pushElement(element);
m_importer.popElement(element.name());
}
};
const Entity& m_entity;
public:
entity_export(const Entity& entity) : m_entity(entity)
{
}
void exportXML(XMLImporter& observer)
{
ExportXMLVisitor visitor(observer);
m_entity.forEachKeyValue(visitor);
}
};
inline void entity_copy(Entity& entity, const Entity& other)
{
entity_export exporter(other);
entity_import importer(entity);
exporter.exportXML(importer);
}
template<typename EntityType>
class EntityConstruction
{
public:
typedef EntityClass* type;
static type get(const EntityType& entity)
{
return &entity.getEntity().getEntityClass();
}
static void copy(EntityType& entity, const EntityType& other)
{
entity_copy(entity.getEntity(), other.getEntity());
}
};
#endif

View File

@ -0,0 +1,2 @@
#include "fs_filesystem.h"

View File

@ -0,0 +1,160 @@
#if !defined(INCLUDED_FS_FILESYSTEM_H)
#define INCLUDED_FS_FILESYSTEM_H
#include "string/string.h"
#include "os/path.h"
#include <map>
inline unsigned int path_get_depth(const char* path)
{
unsigned int depth = 0;
while(path != 0 && path[0] != '\0')
{
path = strchr(path, '/');
if(path != 0)
{
++path;
}
++depth;
}
return depth;
}
/// \brief A generic unix-style file-system which maps paths to files and directories.
/// Provides average O(log n) find and insert methods.
/// \param file_type The data type which represents a file.
template<typename file_type>
class GenericFileSystem
{
class Path
{
CopiedString m_path;
unsigned int m_depth;
public:
Path(const char* path)
: m_path(path), m_depth(path_get_depth(c_str()))
{
}
Path(const char* start, const char* finish)
: m_path(start, finish), m_depth(path_get_depth(c_str()))
{
}
bool operator<(const Path& other) const
{
return string_less_nocase(c_str(), other.c_str());
}
unsigned int depth() const
{
return m_depth;
}
const char* c_str() const
{
return m_path.c_str();
}
};
class Entry
{
file_type* m_file;
public:
Entry(file_type* file)
: m_file(file)
{
}
file_type* file() const
{
return m_file;
}
bool is_directory() const
{
return file() == 0;
}
};
typedef std::map<Path, Entry> Entries;
Entries m_entries;
public:
typedef typename Entries::iterator iterator;
typedef typename Entries::value_type value_type;
iterator begin()
{
return m_entries.begin();
}
iterator end()
{
return m_entries.end();
}
/// \brief Adds the file \p entry at \p path.
/// Creates all directories below \p path if they do not exist.
/// O(log n) on average.
void insert(const Path& path, const Entry& entry)
{
{
const char* end = path_remove_directory(path.c_str());
while(end[0] != '\0')
{
Path dir(path.c_str(), end);
m_entries.insert(value_type(dir, Entry(0)));
end = path_remove_directory(end);
}
}
m_entries.insert(value_type(path, entry));
}
/// \brief Returns the file at \p path or end() if not found.
iterator find(const Path& path)
{
return m_entries.find(path);
}
iterator begin(const char* root)
{
if(root[0] == '\0')
{
return m_entries.begin();
}
iterator i = m_entries.find(root);
if(i == m_entries.end())
{
return i;
}
return ++i;
}
/// \brief Performs a depth-first traversal of the file-system subtree rooted at \p root.
/// Traverses the entire tree if \p root is "".
/// Calls \p visitor.file() with the path to each file relative to the filesystem root.
/// Calls \p visitor.directory() with the path to each directory relative to the filesystem root.
template<typename visitor_type>
void traverse(visitor_type visitor, const char* root)
{
unsigned int start_depth = path_get_depth(root);
unsigned int skip_depth = 0;
for(iterator i = begin(root); i != end() && i->first.depth() > start_depth; ++i)
{
if(i->first.depth() == skip_depth)
{
skip_depth = 0;
}
if(skip_depth == 0)
{
if(!i->second.is_directory())
{
visitor.file(i->first.c_str());
}
else if(visitor.directory(i->first.c_str(), i->first.depth() - start_depth))
{
skip_depth = i->first.depth();
}
}
}
}
};
#endif

View File

@ -0,0 +1,2 @@
#include "fs_path.h"

72
tools/urt/libs/fs_path.h Normal file
View File

@ -0,0 +1,72 @@
#if !defined(INCLUDED_FS_PATH_H)
#define INCLUDED_FS_PATH_H
#include "stream/stringstream.h"
/// \brief A unix-style path string which can be modified at runtime.
///
/// - Maintains a path ending in a path-separator.
/// - Provides a limited STL-style interface to push and pop file or directory names at the end of the path.
class UnixPath
{
StringBuffer m_string;
void check_separator()
{
if(!empty() && m_string.back() != '/')
{
m_string.push_back('/');
}
}
public:
/// \brief Constructs with the directory \p root.
UnixPath(const char* root)
: m_string(root)
{
check_separator();
}
bool empty() const
{
return m_string.empty();
}
const char* c_str() const
{
return m_string.c_str();
}
/// \brief Appends the directory \p name.
void push(const char* name)
{
m_string.push_string(name);
check_separator();
}
/// \brief Appends the directory [\p first, \p last).
void push(const char* first, const char* last)
{
m_string.push_range(first, last);
check_separator();
}
/// \brief Appends the filename \p name.
void push_filename(const char* name)
{
m_string.push_string(name);
}
/// \brief Removes the last directory or filename appended.
void pop()
{
if(m_string.back() == '/')
{
m_string.pop_back();
}
while(!empty() && m_string.back() != '/')
{
m_string.pop_back();
}
}
};
#endif

View File

@ -0,0 +1,3 @@
#include "arrayrange.h"

View File

@ -0,0 +1,52 @@
#if !defined(INCLUDED_GENERIC_ARRAYRANGE_H)
#define INCLUDED_GENERIC_ARRAYRANGE_H
/// \file
/// \brief Macros for automatically converting a compile-time-sized array to a range.
template<typename Element>
struct ArrayRange
{
typedef Element* Iterator;
ArrayRange(Iterator _begin, Iterator _end)
: begin(_begin), end(_end)
{
}
Iterator begin;
Iterator end;
};
template<typename Element>
inline ArrayRange<Element> makeArrayRange(Element* begin, Element* end)
{
return ArrayRange<Element>(begin, end);
}
template<typename Element>
struct ArrayConstRange
{
typedef const Element* Iterator;
ArrayConstRange(Iterator _begin, Iterator _end)
: begin(_begin), end(_end)
{
}
Iterator begin;
Iterator end;
};
template<typename Element>
inline ArrayConstRange<Element> makeArrayRange(const Element* begin, const Element* end)
{
return ArrayConstRange<Element>(begin, end);
}
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array))
#define ARRAY_END(array) (array + ARRAY_SIZE(array))
#define ARRAY_RANGE(array) (makeArrayRange(array, ARRAY_END(array)))
typedef ArrayConstRange<const char*> StringArrayRange;
#define STRING_ARRAY_RANGE(array) (StringArrayRange(array, ARRAY_END(array)))
#endif

View File

@ -0,0 +1,3 @@
#include "bitfield.h"

View File

@ -0,0 +1,113 @@
#if !defined(INCLUDED_GENERIC_BITFIELD_H)
#define INCLUDED_GENERIC_BITFIELD_H
/// \file
/// \brief Type safe bitfield.
/// \brief A bit-field value.
///
/// - Can be forward-declared when the definition of Enumeration is unknown.
/// - Can only be constructed from valid enumerated values.
/// - Can only be compared and combined with others of the same type.
///
/// \param Enumeration A type that contains an enum \c Value of the bits that can be set in this field.
template<typename Enumeration>
class BitFieldValue : public Enumeration
{
unsigned m_value;
protected:
explicit BitFieldValue(unsigned value) : m_value(value)
{
}
public:
BitFieldValue() : m_value(0)
{
}
explicit BitFieldValue(typename Enumeration::Value value) : m_value(1 << value)
{
}
unsigned get() const
{
return m_value;
}
};
template<typename Enumeration>
class BitFieldValueUnsafe : public BitFieldValue<Enumeration>
{
public:
explicit BitFieldValueUnsafe(unsigned value) : BitFieldValue<Enumeration>(value)
{
}
};
template<typename Enumeration>
inline bool operator==(BitFieldValue<Enumeration> self, BitFieldValue<Enumeration> other)
{
return self.get() == other.get();
}
template<typename Enumeration>
inline bool operator!=(BitFieldValue<Enumeration> self, BitFieldValue<Enumeration> other)
{
return !operator==(self, other);
}
template<typename Enumeration>
inline BitFieldValue<Enumeration> operator|(BitFieldValue<Enumeration> self, BitFieldValue<Enumeration> other)
{
return BitFieldValueUnsafe<Enumeration>(self.get() | other.get());
}
template<typename Enumeration>
inline BitFieldValue<Enumeration>& operator|=(BitFieldValue<Enumeration>& self, BitFieldValue<Enumeration> other)
{
return self = self | other;
}
template<typename Enumeration>
inline BitFieldValue<Enumeration> operator&(BitFieldValue<Enumeration> self, BitFieldValue<Enumeration> other)
{
return BitFieldValueUnsafe<Enumeration>(self.get() & other.get());
}
template<typename Enumeration>
inline BitFieldValue<Enumeration>& operator&=(BitFieldValue<Enumeration>& self, BitFieldValue<Enumeration> other)
{
return self = self & other;
}
template<typename Enumeration>
inline BitFieldValue<Enumeration> operator~(BitFieldValue<Enumeration> self)
{
return BitFieldValueUnsafe<Enumeration>(~self.get());
}
inline unsigned int bitfield_enable(unsigned int bitfield, unsigned int mask)
{
return bitfield | mask;
}
inline unsigned int bitfield_disable(unsigned int bitfield, unsigned int mask)
{
return bitfield & ~mask;
}
inline bool bitfield_enabled(unsigned int bitfield, unsigned int mask)
{
return (bitfield & mask) != 0;
}
template<typename Enumeration>
inline BitFieldValue<Enumeration> bitfield_enable(BitFieldValue<Enumeration> bitfield, BitFieldValue<Enumeration> mask)
{
return bitfield | mask;
}
template<typename Enumeration>
inline BitFieldValue<Enumeration> bitfield_disable(BitFieldValue<Enumeration> bitfield, BitFieldValue<Enumeration> mask)
{
return bitfield & ~mask;
}
template<typename Enumeration>
inline bool bitfield_enabled(BitFieldValue<Enumeration> bitfield, BitFieldValue<Enumeration> mask)
{
return (bitfield & mask).get() != 0;
}
#endif

View File

@ -0,0 +1,89 @@
#include "callback.h"
#if defined(_DEBUG) || defined(DOXYGEN)
namespace ExampleMemberCaller
{
// MemberCaller example
class Integer
{
public:
int value;
void printValue() const
{
// print this->value here;
}
void setValue()
{
value = 3;
}
// a typedef to make things more readable
typedef MemberCaller<Integer, &Integer::setValue> SetValueCaller;
};
void example()
{
Integer foo = { 0 };
{
Callback bar = ConstMemberCaller<Integer, &Integer::printValue>(foo);
// invoke the callback
bar(); // foo.printValue()
}
{
// use the typedef to improve readability
Callback bar = Integer::SetValueCaller(foo);
// invoke the callback
bar(); // foo.setValue()
}
}
// end example
}
namespace ExampleReferenceCaller
{
// ReferenceCaller example
void Int_printValue(const int& value)
{
// print value here;
}
void Int_setValue(int& value)
{
value = 3;
}
// a typedef to make things more readable
typedef ReferenceCaller<int, Int_setValue> IntSetValueCaller;
void example()
{
int foo = 0;
{
Callback bar = ConstReferenceCaller<int, Int_printValue>(foo);
// invoke the callback
bar(); // Int_printValue(foo)
}
{
// use the typedef to improve readability
Callback bar = IntSetValueCaller(foo);
// invoke the callback
bar(); // Int_setValue(foo)
}
}
// end example
}
#endif

View File

@ -0,0 +1,517 @@
#if !defined(INCLUDED_GENERIC_CLOSURE_H)
#define INCLUDED_GENERIC_CLOSURE_H
/// \file
/// \brief Type-safe techniques for binding the first argument of an anonymous callback.
#include <cstddef>
/// \brief Combines a void pointer with a pointer to a function which operates on a void pointer.
///
/// Use with the callback constructors MemberCaller, ConstMemberCaller, ReferenceCaller, ConstReferenceCaller, PointerCaller, ConstPointerCaller and FreeCaller.
class Callback
{
typedef void (*Thunk)(void*);
void* m_environment;
Thunk m_thunk;
static void nullThunk(void*)
{
}
public:
Callback() : m_environment(0), m_thunk(nullThunk)
{
}
Callback(void* environment, Thunk function) : m_environment(environment), m_thunk(function)
{
}
void* getEnvironment() const
{
return m_environment;
}
Thunk getThunk() const
{
return m_thunk;
}
void operator()() const
{
m_thunk(m_environment);
}
};
inline bool operator==(const Callback& self, const Callback& other)
{
return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk();
}
inline bool operator<(const Callback& self, const Callback& other)
{
return self.getEnvironment() < other.getEnvironment() ||
(!(other.getEnvironment() < self.getEnvironment()) && self.getThunk() < other.getThunk());
}
/// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and one other argument.
///
/// Use with the callback constructors MemberCaller1, ConstMemberCaller1, ReferenceCaller1, ConstReferenceCaller1, PointerCaller1, ConstPointerCaller1 and FreeCaller1.
template<typename FirstArgument>
class Callback1
{
typedef void (*Thunk)(void*, FirstArgument);
void* m_environment;
Thunk m_thunk;
static void nullThunk(void*, FirstArgument)
{
}
public:
typedef FirstArgument first_argument_type;
Callback1() : m_environment(0), m_thunk(nullThunk)
{
}
Callback1(void* environment, Thunk function) : m_environment(environment), m_thunk(function)
{
}
void* getEnvironment() const
{
return m_environment;
}
Thunk getThunk() const
{
return m_thunk;
}
void operator()(FirstArgument firstArgument) const
{
m_thunk(m_environment, firstArgument);
}
};
template<typename FirstArgument>
inline bool operator==(const Callback1<FirstArgument>& self, const Callback1<FirstArgument>& other)
{
return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk();
}
template<typename FirstArgument>
inline bool operator<(const Callback1<FirstArgument>& self, const Callback1<FirstArgument>& other)
{
return self.getEnvironment() < other.getEnvironment() ||
(!(other.getEnvironment() < self.getEnvironment()) && self.getThunk() < other.getThunk());
}
template<typename Functor>
class FunctorInvoke
{
public:
inline void operator()(Functor functor)
{
functor();
}
};
typedef FunctorInvoke<Callback> CallbackInvoke;
template<typename Functor, typename FirstArgument>
class Functor1Invoke
{
FirstArgument m_firstArgument;
public:
Functor1Invoke(FirstArgument firstArgument) : m_firstArgument(firstArgument)
{
}
inline void operator()(Functor functor)
{
functor(m_firstArgument);
}
};
typedef Callback1<bool> BoolImportCallback;
typedef Callback1<const BoolImportCallback&> BoolExportCallback;
typedef Callback1<int> IntImportCallback;
typedef Callback1<const IntImportCallback&> IntExportCallback;
typedef Callback1<float> FloatImportCallback;
typedef Callback1<const FloatImportCallback&> FloatExportCallback;
typedef Callback1<const char*> StringImportCallback;
typedef Callback1<const StringImportCallback&> StringExportCallback;
typedef Callback1<std::size_t> SizeImportCallback;
typedef Callback1<const SizeImportCallback&> SizeExportCallback;
/// \brief Forms a Callback from a non-const Environment reference and a non-const Environment member-function.
///
/// \dontinclude generic/callback.cpp
/// \skipline MemberCaller example
/// \until end example
template<typename Environment, void (Environment::*member)()>
class MemberCaller
{
Environment& m_environment;
public:
MemberCaller(Environment& environment) : m_environment(environment)
{
}
void* getEnvironment() const
{
return &m_environment;
}
static void thunk(void* environment)
{
((*reinterpret_cast<Environment*>(environment)).*member)();
}
operator Callback() const
{
return Callback(getEnvironment(), thunk);
}
};
/// \brief Forms a Callback from a const Environment reference and a const Environment member-function.
///
/// \dontinclude generic/callback.cpp
/// \skipline MemberCaller example
/// \until end example
template<typename Environment, void (Environment::*member)() const>
class ConstMemberCaller
{
const Environment& m_environment;
public:
ConstMemberCaller(const Environment& environment) : m_environment(environment)
{
}
void* getEnvironment() const
{
return const_cast<Environment*>(&m_environment);
}
static void thunk(void* environment)
{
((*reinterpret_cast<const Environment*>(environment)).*member)();
}
operator Callback() const
{
return Callback(getEnvironment(), thunk);
}
};
/// \brief Forms a Callback from a non-const Environment reference and a const Environment member-function which takes one argument.
template<typename Environment, typename FirstArgument, void (Environment::*member)(FirstArgument)>
class MemberCaller1
{
Environment& m_environment;
public:
MemberCaller1(Environment& environment) : m_environment(environment)
{
}
void* getEnvironment() const
{
return &m_environment;
}
static void thunk(void* environment, FirstArgument firstArgument)
{
((*reinterpret_cast<Environment*>(environment)).*member)(firstArgument);
}
operator Callback1<FirstArgument>() const
{
return Callback1<FirstArgument>(getEnvironment(), thunk);
}
};
/// \brief Forms a Callback from a const Environment reference and a const Environment member-function which takes one argument.
template<typename Environment, typename FirstArgument, void (Environment::*member)(FirstArgument) const>
class ConstMemberCaller1
{
const Environment& m_environment;
public:
ConstMemberCaller1(const Environment& environment) : m_environment(environment)
{
}
void* getEnvironment() const
{
return const_cast<Environment*>(&m_environment);
}
static void thunk(void* environment, FirstArgument firstArgument)
{
((*reinterpret_cast<Environment*>(environment)).*member)(firstArgument);
}
operator Callback1<FirstArgument>() const
{
return Callback1<FirstArgument>(getEnvironment(), thunk);
}
};
/// \brief Forms a Callback from a non-const Environment reference and a free function which operates on a non-const Environment reference.
///
/// \dontinclude generic/callback.cpp
/// \skipline ReferenceCaller example
/// \until end example
template<typename Environment, void (*func)(Environment&)>
class ReferenceCaller
{
Environment& m_environment;
public:
ReferenceCaller(Environment& environment) : m_environment(environment)
{
}
void* getEnvironment() const
{
return &m_environment;
}
static void thunk(void* environment)
{
(func)(*reinterpret_cast<Environment*>(environment));
}
operator Callback() const
{
return Callback(getEnvironment(), thunk);
}
};
/// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference.
///
/// \dontinclude generic/callback.cpp
/// \skipline ReferenceCaller example
/// \until end example
template<typename Environment, void (*func)(const Environment&)>
class ConstReferenceCaller
{
const Environment& m_environment;
public:
ConstReferenceCaller(const Environment& environment) : m_environment(environment)
{
}
void* getEnvironment() const
{
return const_cast<Environment*>(&m_environment);
}
static void thunk(void* environment)
{
(func)(*reinterpret_cast<const Environment*>(environment));
}
operator Callback() const
{
return Callback(getEnvironment(), thunk);
}
};
/// \brief Forms a Callback from a non-const Environment reference and a free function which operates on a non-const Environment reference and one other argument.
template<typename Environment, typename FirstArgument, void (*func)(Environment&, FirstArgument)>
class ReferenceCaller1
{
Environment& m_environment;
public:
ReferenceCaller1(Environment& environment) : m_environment(environment)
{
}
void* getEnvironment() const
{
return &m_environment;
}
static void thunk(void* environment, FirstArgument firstArgument)
{
(func)(*reinterpret_cast<Environment*>(environment), firstArgument);
}
operator Callback1<FirstArgument>() const
{
return Callback1<FirstArgument>(getEnvironment(), thunk);
}
};
/// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference and one other argument.
template<typename Environment, typename FirstArgument, void (*func)(const Environment&, FirstArgument)>
class ConstReferenceCaller1
{
const Environment& m_environment;
public:
ConstReferenceCaller1(const Environment& environment) : m_environment(environment)
{
}
void* getEnvironment() const
{
return const_cast<Environment*>(&m_environment);
}
static void thunk(void* environment, FirstArgument firstArgument)
{
(func)(*reinterpret_cast<const Environment*>(environment), firstArgument);
}
operator Callback1<FirstArgument>() const
{
return Callback1<FirstArgument>(getEnvironment(), thunk);
}
};
/// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer.
template<typename Environment, void (*func)(Environment*)>
class PointerCaller
{
Environment* m_environment;
public:
PointerCaller(Environment* environment) : m_environment(environment)
{
}
void* getEnvironment() const
{
return m_environment;
}
static void thunk(void* environment)
{
(func)(reinterpret_cast<Environment*>(environment));
}
operator Callback() const
{
return Callback(getEnvironment(), thunk);
}
};
/// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer.
template<typename Environment, void (*func)(const Environment*)>
class ConstPointerCaller
{
const Environment* m_environment;
public:
ConstPointerCaller(const Environment* environment) : m_environment(environment)
{
}
void* getEnvironment() const
{
return const_cast<Environment*>(m_environment);
}
static void thunk(void* environment)
{
(func)(reinterpret_cast<const Environment*>(environment));
}
operator Callback() const
{
return Callback(getEnvironment(), thunk);
}
};
/// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer and one other argument.
template<typename Environment, typename FirstArgument, void (*func)(Environment*, FirstArgument)>
class PointerCaller1
{
Environment* m_environment;
public:
PointerCaller1(Environment* environment) : m_environment(environment)
{
}
void* getEnvironment() const
{
return m_environment;
}
static void thunk(void* environment, FirstArgument firstArgument)
{
(func)(reinterpret_cast<Environment*>(environment), firstArgument);
}
operator Callback1<FirstArgument>() const
{
return Callback1<FirstArgument>(getEnvironment(), thunk);
}
};
/// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer and one other argument.
template<typename Environment, typename FirstArgument, void (*func)(const Environment*, FirstArgument)>
class ConstPointerCaller1
{
const Environment* m_environment;
public:
ConstPointerCaller1(const Environment* environment) : m_environment(environment)
{
}
void* getEnvironment() const
{
return const_cast<Environment*>(m_environment);
}
static void thunk(void* environment, FirstArgument firstArgument)
{
(func)(reinterpret_cast<const Environment*>(environment), firstArgument);
}
operator Callback1<FirstArgument>() const
{
return Callback1<FirstArgument>(getEnvironment(), thunk);
}
};
/// \brief Forms a Callback from a free function which takes no arguments.
template<void (*func)()>
class FreeCaller
{
public:
void* getEnvironment() const
{
return 0;
}
static void thunk(void*)
{
(func)();
}
operator Callback() const
{
return Callback(getEnvironment(), thunk);
}
};
/// \brief Forms a Callback from a free function which takes a single argument.
template<typename FirstArgument, void (*func)(FirstArgument)>
class FreeCaller1
{
public:
void* getEnvironment() const
{
return 0;
}
static void thunk(void*, FirstArgument firstArgument)
{
(func)(firstArgument);
}
operator Callback1<FirstArgument>() const
{
return Callback1<FirstArgument>(getEnvironment(), thunk);
}
};
/// \brief Constructs a Callback from a non-const \p functor with zero arguments.
///
/// \param Functor Must define \c operator()().
template<typename Functor>
inline Callback makeCallback(Functor& functor)
{
return Callback(MemberCaller<Functor, &Functor::operator()>(functor));
}
/// \brief Constructs a Callback from a const \p functor with zero arguments.
///
/// \param Functor Must define const \c operator()().
template<typename Functor>
inline Callback makeCallback(const Functor& functor)
{
return Callback(ConstMemberCaller<Functor, &Functor::operator()>(functor));
}
/// \brief Constructs a Callback1 from a non-const \p functor with one argument.
///
/// \param Functor Must define \c first_argument_type and \c operator()(first_argument_type).
template<typename Functor>
inline Callback1<typename Functor::first_argument_type> makeCallback1(Functor& functor)
{
typedef typename Functor::first_argument_type FirstArgument;
return Callback1<FirstArgument>(MemberCaller1<Functor, FirstArgument, &Functor::operator()>(functor));
}
/// \brief Constructs a Callback1 from a const \p functor with one argument.
///
/// \param Functor Must define \c first_argument_type and const \c operator()(first_argument_type).
template<typename Functor>
inline Callback1<typename Functor::first_argument_type> makeCallback1(const Functor& functor)
{
typedef typename Functor::first_argument_type FirstArgument;
return Callback1<FirstArgument>(ConstMemberCaller1<Functor, FirstArgument, &Functor::operator()>(functor));
}
#endif

View File

@ -0,0 +1,3 @@
#include "enumeration.h"

View File

@ -0,0 +1,40 @@
#if !defined(INCLUDED_GENERIC_ENUMERATION_H)
#define INCLUDED_GENERIC_ENUMERATION_H
/// \file
/// \brief Type safe enumeration.
/// \brief An enumerated value.
///
/// - Can be forward-declared when the definition of Enumeration is unknown.
/// - Can only be constructed from valid enumerated values.
/// - Can only be compared with others of the same type.
///
/// \param Enumeration A type that contains an enum \c Value of the allowed values of the enumeration.
template<typename Enumeration>
class EnumeratedValue : public Enumeration
{
typename Enumeration::Value m_value;
public:
explicit EnumeratedValue(typename Enumeration::Value value) : m_value(value)
{
}
typename Enumeration::Value get() const
{
return m_value;
}
};
template<typename Enumeration>
inline bool operator==(EnumeratedValue<Enumeration> self, EnumeratedValue<Enumeration> other)
{
return self.get() == other.get();
}
template<typename Enumeration>
inline bool operator!=(EnumeratedValue<Enumeration> self, EnumeratedValue<Enumeration> other)
{
return !operator==(self, other);
}
#endif

View File

@ -0,0 +1,21 @@
#include "object.h"
namespace
{
class Blah
{
int i;
public:
Blah()
{
i = 3;
}
};
void Test()
{
char storage[sizeof(Blah)];
constructor(*reinterpret_cast<Blah*>(storage));
}
}

View File

@ -0,0 +1,78 @@
#if !defined(INCLUDED_GENERIC_OBJECT_H)
#define INCLUDED_GENERIC_OBJECT_H
/// \file
/// \brief Convenience functions (syntactic sugar) to wrap explicit constructor (aka in-place 'new') and destructor calls.
///
/// Use makeReference() to wrap non-const-reference constructor parameters.
#if _MSC_VER > 1000 && defined(WIN32)
#pragma warning(disable:4345) // behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized
#endif
#include <new>
template<typename Type>
inline void constructor(Type& object)
{
new(&object) Type();
}
template<typename Type, typename T1>
inline void constructor(Type& object, const T1& t1)
{
new(&object) Type(t1);
}
template<typename Type, typename T1, typename T2>
inline void constructor(Type& object, const T1& t1, const T2& t2)
{
new(&object) Type(t1, t2);
}
template<typename Type, typename T1, typename T2, typename T3>
inline void constructor(Type& object, const T1& t1, const T2& t2, const T3& t3)
{
new(&object) Type(t1, t2, t3);
}
template<typename Type, typename T1, typename T2, typename T3, typename T4>
inline void constructor(Type& object, const T1& t1, const T2& t2, const T3& t3, const T4& t4)
{
new(&object) Type(t1, t2, t3, t4);
}
template<typename Type, typename T1, typename T2, typename T3, typename T4, typename T5>
inline void constructor(Type& object, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5)
{
new(&object) Type(t1, t2, t3, t4, t5);
}
template<typename Type, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
inline void constructor(Type& object, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6)
{
new(&object) Type(t1, t2, t3, t4, t5, t6);
}
template<typename Type, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
inline void constructor(Type& object, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7)
{
new(&object) Type(t1, t2, t3, t4, t5, t6, t7);
}
template<typename Type, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
inline void constructor(Type& object, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7, const T8& t8)
{
new(&object) Type(t1, t2, t3, t4, t5, t6, t7, t8);
}
template<typename Type>
inline void destructor(Type& object)
{
object.~Type();
}
#endif

View File

@ -0,0 +1,2 @@
#include "reference.h"

View File

@ -0,0 +1,111 @@
#if !defined(INCLUDED_GENERIC_REFERENCE_H)
#define INCLUDED_GENERIC_REFERENCE_H
/// \file
/// \brief Wrappers to allow storing objects in templated containers using 'reference' semantics.
/// \brief A reference to a mutable object.
/// Has 'reference' semantics, except for \c 'operator==' and \c 'operator.'.
/// \param Type The type of the referenced object.
template<typename Type>
class Reference
{
Type* m_contained;
public:
explicit Reference(Type& contained) : m_contained(&contained)
{
}
Type& operator*() const
{
return *m_contained;
}
Type* operator->() const
{
return m_contained;
}
operator Type&() const
{
return *m_contained;
}
Type& get() const
{
return *m_contained;
}
Type* get_pointer() const
{
return m_contained;
}
};
template<typename Type>
bool operator<(const Reference<Type>& self, const Reference<Type>& other)
{
return self.get() < other.get();
}
template<typename Type>
bool operator==(const Reference<Type>& self, const Reference<Type>& other)
{
return self.get() == other.get();
}
/// \brief construct a reference to a mutable object.
template<typename Type>
inline Reference<Type> makeReference(Type& value)
{
return Reference<Type>(value);
}
/// \brief A reference to a non-mutable object.
/// Has 'reference' semantics, except for \c 'operator==' and \c 'operator.'.
/// \param Type The type of the referenced object.
template<typename Type>
class ConstReference
{
const Type* m_contained;
public:
explicit ConstReference(const Type& contained) : m_contained(&contained)
{
}
const Type& operator*() const
{
return *m_contained;
}
const Type* operator->() const
{
return m_contained;
}
operator const Type&() const
{
return *m_contained;
}
const Type& get() const
{
return *m_contained;
}
const Type* get_pointer() const
{
return m_contained;
}
};
template<typename Type>
bool operator<(const ConstReference<Type>& self, const ConstReference<Type>& other)
{
return self.get() < other.get();
}
template<typename Type>
bool operator==(const ConstReference<Type>& self, const ConstReference<Type>& other)
{
return self.get() == other.get();
}
/// \brief construct a reference to a non-mutable object.
template<typename Type>
inline ConstReference<Type> makeReference(const Type& value)
{
return ConstReference<Type>(value);
}
#endif

View File

@ -0,0 +1,2 @@
#include "referencecounted.h"

View File

@ -0,0 +1,187 @@
#if !defined(INCLUDED_GENERIC_REFERENCECOUNTED_H)
#define INCLUDED_GENERIC_REFERENCECOUNTED_H
/// \file
/// \brief 'smart' pointers and references.
#include <algorithm>
template<typename Type>
class IncRefDecRefCounter
{
public:
void increment(Type& value)
{
value.IncRef();
}
void decrement(Type& value)
{
value.DecRef();
}
};
/// \brief A smart-pointer that uses a counter stored in the object pointed-to.
template<typename Type, typename Counter = IncRefDecRefCounter<Type> >
class SmartPointer : public Counter
{
Type* m_value;
public:
SmartPointer(const SmartPointer& other)
: m_value(other.m_value)
{
Counter::increment(*m_value);
}
explicit SmartPointer(Type* value)
: m_value(value)
{
Counter::increment(*m_value);
}
~SmartPointer()
{
Counter::decrement(*m_value);
}
SmartPointer& operator=(const SmartPointer& other)
{
SmartPointer temp(other);
temp.swap(*this);
return *this;
}
SmartPointer& operator=(Type* value)
{
SmartPointer temp(value);
temp.swap(*this);
return *this;
}
void swap(SmartPointer& other)
{
std::swap(m_value, other.m_value);
}
operator Type*() const
{
return m_value;
}
Type& operator*() const
{
return *m_value;
}
Type* operator->() const
{
return m_value;
}
Type* get() const
{
return m_value;
}
};
template<typename Type>
inline bool operator<(const SmartPointer<Type>& self, const SmartPointer<Type>& other)
{
return self.get() < other.get();
}
template<typename Type>
inline bool operator==(const SmartPointer<Type>& self, const SmartPointer<Type>& other)
{
return self.get() == other.get();
}
template<typename Type>
inline bool operator!=(const SmartPointer<Type>& self, const SmartPointer<Type>& other)
{
return !::operator==(self, other);
}
namespace std
{
/// \brief Swaps the values of \p self and \p other.
/// Overloads std::swap().
template<typename Type>
inline void swap(SmartPointer<Type>& self, SmartPointer<Type>& other)
{
self.swap(other);
}
}
/// \brief A smart-reference that uses a counter stored in the object pointed-to.
template<typename Type, typename Counter = IncRefDecRefCounter<Type> >
class SmartReference : public Counter
{
Type* m_value;
public:
SmartReference(const SmartReference& other)
: m_value(other.m_value)
{
Counter::increment(*m_value);
}
explicit SmartReference(Type& value)
: m_value(&value)
{
Counter::increment(*m_value);
}
~SmartReference()
{
Counter::decrement(*m_value);
}
SmartReference& operator=(const SmartReference& other)
{
SmartReference temp(other);
temp.swap(*this);
return *this;
}
SmartReference& operator=(Type& value)
{
SmartReference temp(value);
temp.swap(*this);
return *this;
}
void swap(SmartReference& other)
{
std::swap(m_value, other.m_value);
}
operator Type&() const
{
return *m_value;
}
Type& get() const
{
return *m_value;
}
Type* get_pointer() const
{
return m_value;
}
};
template<typename Type>
inline bool operator<(const SmartReference<Type>& self, const SmartReference<Type>& other)
{
return self.get() < other.get();
}
template<typename Type>
inline bool operator==(const SmartReference<Type>& self, const SmartReference<Type>& other)
{
return self.get() == other.get();
}
template<typename Type>
inline bool operator!=(const SmartReference<Type>& self, const SmartReference<Type>& other)
{
return !::operator==(self, other);
}
namespace std
{
/// \brief Swaps the values of \p self and \p other.
/// Overloads std::swap().
template<typename Type>
inline void swap(SmartReference<Type>& self, SmartReference<Type>& other)
{
self.swap(other);
}
}
#endif

View File

@ -0,0 +1,113 @@
#include "static.h"
#if defined(_DEBUG) || defined(DOXYGEN)
namespace ExampleStatic
{
// Static example
// ---- myclass.h
class MyClass
{
public:
int value;
MyClass() : value(3)
{
}
};
typedef Static<MyClass> StaticMyClass;
// ---- main.cpp
class DynamicInitialisation
{
public:
DynamicInitialisation()
{
// StaticMyClass::instance() may be invalid here because construction order is undefined
}
};
DynamicInitialisation g_dynamicInitialisation;
void duringMain()
{
int bar = StaticMyClass::instance().value;
}
// end example
}
namespace ExampleLazyStatic
{
// LazyStatic example
// ---- myclass.h
class MyClass
{
public:
int value;
MyClass() : value(3)
{
}
// destructor will never be called
};
typedef LazyStatic<MyClass> StaticMyClass;
// ---- main.cpp
class DynamicInitialisation
{
public:
DynamicInitialisation()
{
int bar = StaticMyClass::instance().value;
}
};
DynamicInitialisation g_dynamicInitialisation;
void duringMain()
{
int bar = StaticMyClass::instance().value;
}
// end example
}
namespace ExampleSmartStatic
{
// SmartStatic example
// ---- myclass.h
class MyClass
{
public:
int value;
MyClass() : value(3)
{
}
};
typedef CountedStatic<MyClass> StaticMyClass;
// ---- main.cpp
class DynamicInitialisation
{
public:
DynamicInitialisation()
{
// StaticMyClass::instance() is invalid before the ref is constructed
SmartStatic<MyClass> ref;
int bar = ref.instance().value;
SmartStatic<MyClass> ref2; // any number of instances are allowed.
}
};
DynamicInitialisation g_dynamicInitialisation;
void duringMain()
{
int bar = SmartStatic<MyClass>().instance().value; // an instance can be a temporary
}
// end example
}
#endif

View File

@ -0,0 +1,123 @@
#if !defined(INCLUDED_GENERIC_STATIC_H)
#define INCLUDED_GENERIC_STATIC_H
/// \file
/// \brief Template techniques for instantiating singletons.
#include <cstddef>
/// \brief A singleton which is statically initialised.
///
/// \param Type The singleton object type.
///
/// \dontinclude generic/static.cpp
/// \skipline Static example
/// \until end example
template<typename Type>
class Static
{
static Type m_instance;
public:
static Type& instance()
{
return m_instance;
}
};
template<typename Type>
Type Static<Type>::m_instance;
/// \brief A singleton which is lazily initialised.
/// The instance is constructed the first time it is referenced, and is never destroyed.
///
/// \param Type The singleton object type.
///
/// \dontinclude generic/static.cpp
/// \skipline LazyStatic example
/// \until end example
template<typename Type>
class LazyStatic
{
static Type* m_instance; // this will be initialised to 0 by the CRT, according to the c++ standard
public:
static Type& instance()
{
if(m_instance == 0)
{
m_instance = new Type; // allocate using 'new' to get the correct alignment
}
return *m_instance;
}
};
template<typename Type>
Type* LazyStatic<Type>::m_instance;
/// \brief A singleton which keeps a count of the number of times it is referenced.
///
/// The instance is constructed when its reference count changes from 0 to 1 and destroyed when its reference count changes from 1 to 0.
/// Use with SmartStatic.
///
/// \param Type The singleton object type.
template<typename Type>
class CountedStatic
{
static std::size_t m_refcount; // this will be initialised to 0 by the CRT, according to the c++ standard
static Type* m_instance;
public:
static Type& instance()
{
return *m_instance;
}
static void capture()
{
if(++m_refcount == 1)
{
m_instance = new Type; // allocate using 'new' to get the correct alignment
}
}
static void release()
{
if(--m_refcount == 0)
{
delete m_instance;
}
}
};
template<typename Type>
std::size_t CountedStatic<Type>::m_refcount; // this will be initialised to 0 by the CRT, according to the c++ standard
template<typename Type>
Type* CountedStatic<Type>::m_instance;
/// \brief A reference to a CountedStatic.
/// Guarantees that CountedStatic<Type> will be constructed for the lifetime of this object.
///
/// \param Type The type parameter of the CountedStatic to reference.
///
/// \dontinclude generic/static.cpp
/// \skipline SmartStatic example
/// \until end example
template<typename Type>
class SmartStatic
{
public:
SmartStatic()
{
CountedStatic<Type>::capture();
}
~SmartStatic()
{
CountedStatic<Type>::release();
}
Type& instance()
{
return CountedStatic<Type>::instance();
}
};
#endif

View File

@ -0,0 +1,527 @@
#include "accelerator.h"
#include "debugging/debugging.h"
#include <map>
#include <set>
#include <gtk/gtkwindow.h>
#include <gtk/gtkaccelgroup.h>
#include "generic/callback.h"
#include "generic/bitfield.h"
#include "pointer.h"
#include "closure.h"
typedef std::map<Accelerator, Callback> AcceleratorMap;
void accelerator_map_insert(AcceleratorMap& acceleratorMap, Accelerator accelerator, const Callback& callback)
{
if(accelerator.key != 0)
{
ASSERT_MESSAGE(acceleratorMap.find(accelerator) == acceleratorMap.end(), "failed to add accelerator");
acceleratorMap.insert(AcceleratorMap::value_type(accelerator, callback));
}
}
void accelerator_map_erase(AcceleratorMap& acceleratorMap, Accelerator accelerator)
{
if(accelerator.key != 0)
{
ASSERT_MESSAGE(acceleratorMap.find(accelerator) != acceleratorMap.end(), "failed to remove accelerator");
acceleratorMap.erase(accelerator);
}
}
Accelerator accelerator_for_event_key(guint keyval, guint state)
{
keyval = gdk_keyval_to_upper(keyval);
if(keyval == GDK_ISO_Left_Tab)
keyval = GDK_Tab;
return Accelerator(keyval, (GdkModifierType)(state & gtk_accelerator_get_default_mod_mask()));
}
bool AcceleratorMap_activate(const AcceleratorMap& acceleratorMap, const Accelerator& accelerator)
{
AcceleratorMap::const_iterator i = acceleratorMap.find(accelerator);
if(i != acceleratorMap.end())
{
(*i).second();
return true;
}
return false;
}
static gboolean accelerator_key_event(GtkWindow* window, GdkEventKey* event, AcceleratorMap* acceleratorMap)
{
return AcceleratorMap_activate(*acceleratorMap, accelerator_for_event_key(event->keyval, event->state));
}
AcceleratorMap g_special_accelerators;
namespace MouseButton
{
enum
{
Left = 1 << 0,
Right = 1 << 1,
Middle = 1 << 2,
};
}
typedef unsigned int ButtonMask;
void print_buttons(ButtonMask mask)
{
globalOutputStream() << "button state: ";
if((mask & MouseButton::Left) != 0)
{
globalOutputStream() << "Left ";
}
if((mask & MouseButton::Right) != 0)
{
globalOutputStream() << "Right ";
}
if((mask & MouseButton::Middle) != 0)
{
globalOutputStream() << "Middle ";
}
globalOutputStream() << "\n";
}
ButtonMask ButtonMask_for_event_button(guint button)
{
switch(button)
{
case 1:
return MouseButton::Left;
case 2:
return MouseButton::Middle;
case 3:
return MouseButton::Right;
}
return 0;
}
bool window_has_accel(GtkWindow* toplevel)
{
return g_slist_length(gtk_accel_groups_from_object(G_OBJECT(toplevel))) != 0;
}
namespace
{
bool g_accel_enabled = true;
}
bool global_accel_enabled()
{
return g_accel_enabled;
}
AcceleratorMap g_queuedAccelerators;
GClosure* accel_group_add_accelerator(GtkAccelGroup* group, Accelerator accelerator, const Callback& callback);
void GlobalQueuedAccelerators_commit()
{
for(AcceleratorMap::const_iterator i = g_queuedAccelerators.begin(); i != g_queuedAccelerators.end(); ++i)
{
accel_group_add_accelerator(global_accel, (*i).first, (*i).second);
}
g_queuedAccelerators.clear();
}
void GlobalQueuedAccelerators_add(Accelerator accelerator, const Callback& callback)
{
g_queuedAccelerators.insert(AcceleratorMap::value_type(accelerator, callback));
}
void accel_group_test(GtkWindow* toplevel, GtkAccelGroup* accel)
{
guint n_entries;
gtk_accel_group_query(accel, '4', (GdkModifierType)0, &n_entries);
globalOutputStream() << "grid4: " << n_entries << "\n";
globalOutputStream() << "toplevel accelgroups: " << g_slist_length(gtk_accel_groups_from_object(G_OBJECT(toplevel))) << "\n";
}
typedef std::set<GtkWindow*> WindowSet;
WindowSet g_accel_windows;
bool Buttons_press(ButtonMask& buttons, guint button, guint state)
{
if(buttons == 0 && bitfield_enable(buttons, ButtonMask_for_event_button(button)) != 0)
{
ASSERT_MESSAGE(g_accel_enabled, "Buttons_press: accelerators not enabled");
g_accel_enabled = false;
for(WindowSet::iterator i = g_accel_windows.begin(); i != g_accel_windows.end(); ++i)
{
GtkWindow* toplevel = *i;
ASSERT_MESSAGE(window_has_accel(toplevel), "ERROR");
ASSERT_MESSAGE(GTK_WIDGET_TOPLEVEL(toplevel), "disabling accel for non-toplevel window");
gtk_window_remove_accel_group(toplevel, global_accel);
#if 0
globalOutputStream() << reinterpret_cast<unsigned int>(toplevel) << ": disabled global accelerators\n";
#endif
#if 0
accel_group_test(toplevel, global_accel);
#endif
}
}
buttons = bitfield_enable(buttons, ButtonMask_for_event_button(button));
#if 0
globalOutputStream() << "Buttons_press: ";
print_buttons(buttons);
#endif
return false;
}
bool Buttons_release(ButtonMask& buttons, guint button, guint state)
{
if(buttons != 0 && bitfield_disable(buttons, ButtonMask_for_event_button(button)) == 0)
{
ASSERT_MESSAGE(!g_accel_enabled, "Buttons_release: accelerators are enabled");
g_accel_enabled = true;
for(WindowSet::iterator i = g_accel_windows.begin(); i != g_accel_windows.end(); ++i)
{
GtkWindow* toplevel = *i;
ASSERT_MESSAGE(!window_has_accel(toplevel), "ERROR");
ASSERT_MESSAGE(GTK_WIDGET_TOPLEVEL(toplevel), "enabling accel for non-toplevel window");
gtk_window_add_accel_group(toplevel, global_accel);
#if 0
globalOutputStream() << reinterpret_cast<unsigned int>(toplevel) << ": enabled global accelerators\n";
#endif
#if 0
accel_group_test(toplevel, global_accel);
#endif
}
GlobalQueuedAccelerators_commit();
}
buttons = bitfield_disable(buttons, ButtonMask_for_event_button(button));
#if 0
globalOutputStream() << "Buttons_release: ";
print_buttons(buttons);
#endif
return false;
}
bool Buttons_releaseAll(ButtonMask& buttons)
{
Buttons_release(buttons, MouseButton::Left | MouseButton::Middle | MouseButton::Right, 0);
return false;
}
struct PressedButtons
{
ButtonMask buttons;
PressedButtons() : buttons(0)
{
}
};
gboolean PressedButtons_button_press(GtkWidget* widget, GdkEventButton* event, PressedButtons* pressed)
{
if(event->type == GDK_BUTTON_PRESS)
{
return Buttons_press(pressed->buttons, event->button, event->state);
}
return FALSE;
}
gboolean PressedButtons_button_release(GtkWidget* widget, GdkEventButton* event, PressedButtons* pressed)
{
if(event->type == GDK_BUTTON_RELEASE)
{
return Buttons_release(pressed->buttons, event->button, event->state);
}
return FALSE;
}
gboolean PressedButtons_focus_out(GtkWidget* widget, GdkEventFocus* event, PressedButtons* pressed)
{
Buttons_releaseAll(pressed->buttons);
return FALSE;
}
void PressedButtons_connect(PressedButtons& pressedButtons, GtkWidget* widget)
{
g_signal_connect(G_OBJECT(widget), "button_press_event", G_CALLBACK(PressedButtons_button_press), &pressedButtons);
g_signal_connect(G_OBJECT(widget), "button_release_event", G_CALLBACK(PressedButtons_button_release), &pressedButtons);
g_signal_connect(G_OBJECT(widget), "focus_out_event", G_CALLBACK(PressedButtons_focus_out), &pressedButtons);
}
PressedButtons g_pressedButtons;
#include <set>
struct PressedKeys
{
typedef std::set<guint> Keys;
Keys keys;
std::size_t refcount;
PressedKeys() : refcount(0)
{
}
};
AcceleratorMap g_keydown_accelerators;
AcceleratorMap g_keyup_accelerators;
bool Keys_press(PressedKeys::Keys& keys, guint keyval)
{
if(keys.insert(keyval).second)
{
return AcceleratorMap_activate(g_keydown_accelerators, accelerator_for_event_key(keyval, 0));
}
return g_keydown_accelerators.find(accelerator_for_event_key(keyval, 0)) != g_keydown_accelerators.end();
}
bool Keys_release(PressedKeys::Keys& keys, guint keyval)
{
if(keys.erase(keyval) != 0)
{
return AcceleratorMap_activate(g_keyup_accelerators, accelerator_for_event_key(keyval, 0));
}
return g_keyup_accelerators.find(accelerator_for_event_key(keyval, 0)) != g_keyup_accelerators.end();
}
void Keys_releaseAll(PressedKeys::Keys& keys, guint state)
{
for(PressedKeys::Keys::iterator i = keys.begin(); i != keys.end(); ++i)
{
AcceleratorMap_activate(g_keyup_accelerators, accelerator_for_event_key(*i, state));
}
keys.clear();
}
gboolean PressedKeys_key_press(GtkWidget* widget, GdkEventKey* event, PressedKeys* pressedKeys)
{
//globalOutputStream() << "pressed: " << event->keyval << "\n";
return event->state == 0 && Keys_press(pressedKeys->keys, event->keyval);
}
gboolean PressedKeys_key_release(GtkWidget* widget, GdkEventKey* event, PressedKeys* pressedKeys)
{
//globalOutputStream() << "released: " << event->keyval << "\n";
return Keys_release(pressedKeys->keys, event->keyval);
}
gboolean PressedKeys_focus_in(GtkWidget* widget, GdkEventFocus* event, PressedKeys* pressedKeys)
{
++pressedKeys->refcount;
return FALSE;
}
gboolean PressedKeys_focus_out(GtkWidget* widget, GdkEventFocus* event, PressedKeys* pressedKeys)
{
if(--pressedKeys->refcount == 0)
{
Keys_releaseAll(pressedKeys->keys, 0);
}
return FALSE;
}
PressedKeys g_pressedKeys;
void GlobalPressedKeys_releaseAll()
{
Keys_releaseAll(g_pressedKeys.keys, 0);
}
void GlobalPressedKeys_connect(GtkWindow* window)
{
unsigned int key_press_handler = g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(PressedKeys_key_press), &g_pressedKeys);
unsigned int key_release_handler = g_signal_connect(G_OBJECT(window), "key_release_event", G_CALLBACK(PressedKeys_key_release), &g_pressedKeys);
g_object_set_data(G_OBJECT(window), "key_press_handler", gint_to_pointer(key_press_handler));
g_object_set_data(G_OBJECT(window), "key_release_handler", gint_to_pointer(key_release_handler));
unsigned int focus_in_handler = g_signal_connect(G_OBJECT(window), "focus_in_event", G_CALLBACK(PressedKeys_focus_in), &g_pressedKeys);
unsigned int focus_out_handler = g_signal_connect(G_OBJECT(window), "focus_out_event", G_CALLBACK(PressedKeys_focus_out), &g_pressedKeys);
g_object_set_data(G_OBJECT(window), "focus_in_handler", gint_to_pointer(focus_in_handler));
g_object_set_data(G_OBJECT(window), "focus_out_handler", gint_to_pointer(focus_out_handler));
}
void GlobalPressedKeys_disconnect(GtkWindow* window)
{
g_signal_handler_disconnect(G_OBJECT(window), gpointer_to_int(g_object_get_data(G_OBJECT(window), "key_press_handler")));
g_signal_handler_disconnect(G_OBJECT(window), gpointer_to_int(g_object_get_data(G_OBJECT(window), "key_release_handler")));
g_signal_handler_disconnect(G_OBJECT(window), gpointer_to_int(g_object_get_data(G_OBJECT(window), "focus_in_handler")));
g_signal_handler_disconnect(G_OBJECT(window), gpointer_to_int(g_object_get_data(G_OBJECT(window), "focus_out_handler")));
}
void special_accelerators_add(Accelerator accelerator, const Callback& callback)
{
accelerator_map_insert(g_special_accelerators, accelerator, callback);
}
void special_accelerators_remove(Accelerator accelerator)
{
accelerator_map_erase(g_special_accelerators, accelerator);
}
void keydown_accelerators_add(Accelerator accelerator, const Callback& callback)
{
accelerator_map_insert(g_keydown_accelerators, accelerator, callback);
}
void keydown_accelerators_remove(Accelerator accelerator)
{
accelerator_map_erase(g_keydown_accelerators, accelerator);
}
void keyup_accelerators_add(Accelerator accelerator, const Callback& callback)
{
accelerator_map_insert(g_keyup_accelerators, accelerator, callback);
}
void keyup_accelerators_remove(Accelerator accelerator)
{
accelerator_map_erase(g_keyup_accelerators, accelerator);
}
gboolean accel_closure_callback(GtkAccelGroup* group, GtkWidget* widget, guint key, GdkModifierType modifiers, gpointer data)
{
(*reinterpret_cast<Callback*>(data))();
return TRUE;
}
GClosure* accel_group_add_accelerator(GtkAccelGroup* group, Accelerator accelerator, const Callback& callback)
{
if(accelerator.key != 0 && gtk_accelerator_valid(accelerator.key, accelerator.modifiers))
{
//globalOutputStream() << "adding accelerator: " << accelerator.key << " " << accelerator.modifiers << "\n";
GClosure* closure = create_cclosure(G_CALLBACK(accel_closure_callback), callback);
gtk_accel_group_connect(group, accelerator.key, accelerator.modifiers, GTK_ACCEL_VISIBLE, closure);
return closure;
}
else
{
special_accelerators_add(accelerator, callback);
return 0;
}
}
void accel_group_remove_accelerator(GtkAccelGroup* group, Accelerator accelerator)
{
if(accelerator.key != 0 && gtk_accelerator_valid(accelerator.key, accelerator.modifiers))
{
gtk_accel_group_disconnect_key(group, accelerator.key, accelerator.modifiers);
}
else
{
special_accelerators_remove(accelerator);
}
}
GtkAccelGroup* global_accel = 0;
void global_accel_init()
{
global_accel = gtk_accel_group_new();
}
void global_accel_destroy()
{
g_object_unref(global_accel);
}
GClosure* global_accel_group_add_accelerator(Accelerator accelerator, const Callback& callback)
{
if(!global_accel_enabled())
{
// workaround: cannot add to GtkAccelGroup while it is disabled
GlobalQueuedAccelerators_add(accelerator, callback);
return 0;
}
return accel_group_add_accelerator(global_accel, accelerator, callback);
}
void global_accel_group_remove_accelerator(Accelerator accelerator)
{
//ASSERT_MESSAGE(global_accel_enabled(), "removing accelerator while global accel is disabled");
accel_group_remove_accelerator(global_accel, accelerator);
}
/// \brief Propagates key events to the focus-widget, overriding global accelerators.
static gboolean override_global_accelerators(GtkWindow* window, GdkEventKey* event, gpointer data)
{
return gtk_window_propagate_key_event(window, event);
}
void global_accel_connect_window(GtkWindow* window)
{
#if 1
unsigned int override_handler = g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(override_global_accelerators), 0);
g_object_set_data(G_OBJECT(window), "override_handler", gint_to_pointer(override_handler));
unsigned int special_key_press_handler = g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(accelerator_key_event), &g_special_accelerators);
g_object_set_data(G_OBJECT(window), "special_key_press_handler", gint_to_pointer(special_key_press_handler));
GlobalPressedKeys_connect(window);
#else
unsigned int key_press_handler = g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(accelerator_key_event), &g_keydown_accelerators);
unsigned int key_release_handler = g_signal_connect(G_OBJECT(window), "key_release_event", G_CALLBACK(accelerator_key_event), &g_keyup_accelerators);
g_object_set_data(G_OBJECT(window), "key_press_handler", gint_to_pointer(key_press_handler));
g_object_set_data(G_OBJECT(window), "key_release_handler", gint_to_pointer(key_release_handler));
#endif
g_accel_windows.insert(window);
gtk_window_add_accel_group(window, global_accel);
}
void global_accel_disconnect_window(GtkWindow* window)
{
#if 1
GlobalPressedKeys_disconnect(window);
g_signal_handler_disconnect(G_OBJECT(window), gpointer_to_int(g_object_get_data(G_OBJECT(window), "override_handler")));
g_signal_handler_disconnect(G_OBJECT(window), gpointer_to_int(g_object_get_data(G_OBJECT(window), "special_key_press_handler")));
#else
g_signal_handler_disconnect(G_OBJECT(window), gpointer_to_int(g_object_get_data(G_OBJECT(window), "key_press_handler")));
g_signal_handler_disconnect(G_OBJECT(window), gpointer_to_int(g_object_get_data(G_OBJECT(window), "key_release_handler")));
#endif
gtk_window_remove_accel_group(window, global_accel);
std::size_t count = g_accel_windows.erase(window);
ASSERT_MESSAGE(count == 1, "failed to remove accel group\n");
}
GClosure* global_accel_group_find(Accelerator accelerator)
{
guint numEntries = 0;
GtkAccelGroupEntry* entry = gtk_accel_group_query(global_accel, accelerator.key, accelerator.modifiers, &numEntries);
if(numEntries != 0)
{
if(numEntries != 1)
{
char* name = gtk_accelerator_name(accelerator.key, accelerator.modifiers);
globalErrorStream() << "accelerator already in-use: " << name << "\n";
g_free(name);
}
return entry->closure;
}
return 0;
}
void command_connect_accelerator(const Accelerator& accelerator, const Callback& callback)
{
if(accelerator.key != 0)
{
global_accel_group_add_accelerator(accelerator, callback);
}
}
void command_disconnect_accelerator(const Accelerator& accelerator, const Callback& callback)
{
if(accelerator.key != 0)
{
global_accel_group_remove_accelerator(accelerator);
}
}

View File

@ -0,0 +1,97 @@
#if !defined(INCLUDED_GTKUTIL_ACCELERATOR_H)
#define INCLUDED_GTKUTIL_ACCELERATOR_H
#include <gdk/gdktypes.h>
#include <gdk/gdkkeysyms.h>
#include "generic/callback.h"
struct Accelerator
{
Accelerator(guint _key)
: key(_key), modifiers((GdkModifierType)0)
{
}
Accelerator(guint _key, GdkModifierType _modifiers)
: key(_key), modifiers(_modifiers)
{
}
bool operator<(const Accelerator& other) const
{
return key < other.key || (!(other.key < key) && modifiers < other.modifiers);
}
guint key;
GdkModifierType modifiers;
};
inline Accelerator accelerator_null()
{
return Accelerator(0, (GdkModifierType)0);
}
void keydown_accelerators_add(Accelerator accelerator, const Callback& callback);
void keydown_accelerators_remove(Accelerator accelerator);
void keyup_accelerators_add(Accelerator accelerator, const Callback& callback);
void keyup_accelerators_remove(Accelerator accelerator);
typedef struct _GtkWidget GtkWidget;
typedef struct _GtkWindow GtkWindow;
void global_accel_connect_window(GtkWindow* window);
void global_accel_disconnect_window(GtkWindow* window);
void GlobalPressedKeys_releaseAll();
typedef struct _GtkAccelGroup GtkAccelGroup;
extern GtkAccelGroup* global_accel;
void global_accel_init();
void global_accel_destroy();
GClosure* global_accel_group_find(Accelerator accelerator);
void command_connect_accelerator(const Accelerator& accelerator, const Callback& callback);
void command_disconnect_accelerator(const Accelerator& accelerator, const Callback& callback);
class Command
{
public:
Callback m_callback;
const Accelerator& m_accelerator;
Command(const Callback& callback, const Accelerator& accelerator) : m_callback(callback), m_accelerator(accelerator)
{
}
};
class Toggle
{
public:
Command m_command;
BoolExportCallback m_exportCallback;
Toggle(const Callback& callback, const Accelerator& accelerator, const BoolExportCallback& exportCallback) : m_command(callback, accelerator), m_exportCallback(exportCallback)
{
}
};
class KeyEvent
{
public:
const Accelerator& m_accelerator;
Callback m_keyDown;
Callback m_keyUp;
KeyEvent(const Accelerator& accelerator, const Callback& keyDown, const Callback& keyUp) : m_accelerator(accelerator), m_keyDown(keyDown), m_keyUp(keyUp)
{
}
};
struct PressedButtons;
typedef struct _GtkWidget GtkWidget;
void PressedButtons_connect(PressedButtons& pressedButtons, GtkWidget* widget);
extern PressedButtons g_pressedButtons;
#endif

View File

@ -0,0 +1,117 @@
#include "button.h"
#include <gtk/gtkradiobutton.h>
#include "stream/textstream.h"
#include "stream/stringstream.h"
#include "generic/callback.h"
#include "image.h"
#include "pointer.h"
void clicked_closure_callback(GtkWidget* widget, gpointer data)
{
(*reinterpret_cast<Callback*>(data))();
}
void button_connect_callback(GtkButton* button, const Callback& callback)
{
#if 1
g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(callback.getThunk()), callback.getEnvironment());
#else
g_signal_connect_closure(G_OBJECT(button), "clicked", create_cclosure(G_CALLBACK(clicked_closure_callback), callback), FALSE);
#endif
}
guint toggle_button_connect_callback(GtkToggleButton* button, const Callback& callback)
{
#if 1
guint handler = g_signal_connect_swapped(G_OBJECT(button), "toggled", G_CALLBACK(callback.getThunk()), callback.getEnvironment());
#else
guint handler = g_signal_connect_closure(G_OBJECT(button), "toggled", create_cclosure(G_CALLBACK(clicked_closure_callback), callback), TRUE);
#endif
g_object_set_data(G_OBJECT(button), "handler", gint_to_pointer(handler));
return handler;
}
void button_set_icon(GtkButton* button, const char* icon)
{
GtkImage* image = new_local_image(icon);
gtk_widget_show(GTK_WIDGET(image));
gtk_container_add(GTK_CONTAINER(button), GTK_WIDGET(image));
}
void toggle_button_set_active_no_signal(GtkToggleButton* button, gboolean active)
{
//globalOutputStream() << "set active: " << active << "\n";
guint handler_id = gpointer_to_int(g_object_get_data(G_OBJECT(button), "handler"));
//guint signal_id = g_signal_lookup("toggled", G_OBJECT_TYPE (button));
//globalOutputStream() << "signal_id: " << signal_id << "\n";
//guint found = g_signal_handler_find(G_OBJECT(button), G_SIGNAL_MATCH_ID, signal_id, 0, 0, 0, 0);
//globalOutputStream() << " handler found: " << found << "\n";
g_signal_handler_block(G_OBJECT(button), handler_id);
gtk_toggle_button_set_active(button, active);
g_signal_handler_unblock(G_OBJECT(button), handler_id);
}
void radio_button_print_state(GtkRadioButton* button)
{
globalOutputStream() << "toggle button: ";
for(GSList* radio = gtk_radio_button_group(button); radio != 0; radio = g_slist_next(radio))
{
globalOutputStream() << gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio->data));
}
globalOutputStream() << "\n";
}
GtkToggleButton* radio_button_get_nth(GtkRadioButton* radio, int index)
{
GSList *group = gtk_radio_button_group(radio);
return GTK_TOGGLE_BUTTON(g_slist_nth_data(group, g_slist_length(group) - index - 1));
}
void radio_button_set_active(GtkRadioButton* radio, int index)
{
//radio_button_print_state(radio);
gtk_toggle_button_set_active(radio_button_get_nth(radio, index), TRUE);
//radio_button_print_state(radio);
}
void radio_button_set_active_no_signal(GtkRadioButton* radio, int index)
{
{
for(GSList* l = gtk_radio_button_get_group(radio); l != 0; l = g_slist_next(l))
{
g_signal_handler_block(G_OBJECT(l->data), gpointer_to_int(g_object_get_data(G_OBJECT(l->data), "handler")));
}
}
radio_button_set_active(radio, index);
{
for(GSList* l = gtk_radio_button_get_group(radio); l != 0; l = g_slist_next(l))
{
g_signal_handler_unblock(G_OBJECT(l->data), gpointer_to_int(g_object_get_data(G_OBJECT(l->data), "handler")));
}
}
}
int radio_button_get_active(GtkRadioButton* radio)
{
//radio_button_print_state(radio);
GSList *group = gtk_radio_button_group(radio);
int index = g_slist_length(group) - 1;
for (; group != 0; group = g_slist_next(group))
{
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(group->data)))
{
break;
}
else
{
index--;
}
}
return index;
}

View File

@ -0,0 +1,23 @@
#if !defined(INCLUDED_GTKUTIL_BUTTON_H)
#define INCLUDED_GTKUTIL_BUTTON_H
typedef struct _GtkButton GtkButton;
typedef struct _GtkToggleButton GtkToggleButton;
typedef struct _GtkRadioButton GtkRadioButton;
typedef int gint;
typedef gint gboolean;
typedef unsigned int guint;
class Callback;
void button_connect_callback(GtkButton* button, const Callback& callback);
guint toggle_button_connect_callback(GtkToggleButton* button, const Callback& callback);
void button_set_icon(GtkButton* button, const char* icon);
void toggle_button_set_active_no_signal(GtkToggleButton* item, gboolean active);
void radio_button_set_active(GtkRadioButton* radio, int index);
void radio_button_set_active_no_signal(GtkRadioButton* radio, int index);
int radio_button_get_active(GtkRadioButton* radio);
#endif

View File

@ -0,0 +1,142 @@
#include "clipboard.h"
#include "stream/memstream.h"
#include "stream/textstream.h"
/// \file
/// \brief Platform-independent GTK clipboard support.
/// \todo Using GDK_SELECTION_CLIPBOARD fails on win32, so we use the win32 API directly for now.
#if defined (__linux__) || defined (__APPLE__)
#include <gtk/gtkclipboard.h>
enum
{
RADIANT_CLIPPINGS = 23,
};
static const GtkTargetEntry clipboard_targets[] = {
{ "RADIANT_CLIPPINGS", 0, RADIANT_CLIPPINGS, },
};
static void clipboard_get (GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gpointer data)
{
std::size_t len = *reinterpret_cast<std::size_t*>(data);
const char* buffer = (len != 0) ? reinterpret_cast<const char*>(data) + sizeof(std::size_t) : 0;
GdkAtom type = GDK_NONE;
if(info == clipboard_targets[0].info)
{
type = gdk_atom_intern(clipboard_targets[0].target, FALSE);
}
gtk_selection_data_set (selection_data, type, 8, reinterpret_cast<const guchar*>(buffer), static_cast<gint>(len));
}
static void clipboard_clear (GtkClipboard *clipboard, gpointer data)
{
delete [] reinterpret_cast<const char*>(data);
}
static void clipboard_received (GtkClipboard *clipboard, GtkSelectionData *data, gpointer user_data)
{
if (data->length < 0)
{
globalErrorStream() << "Error retrieving selection\n";
}
else if(strcmp(gdk_atom_name(data->type), clipboard_targets[0].target) == 0)
{
BufferInputStream istream(reinterpret_cast<const char*>(data->data), data->length);
(*reinterpret_cast<ClipboardPasteFunc*>(user_data))(istream);
}
}
void clipboard_copy(ClipboardCopyFunc copy)
{
GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
BufferOutputStream ostream;
copy(ostream);
std::size_t length = ostream.size();
char* data = new char[length + sizeof(std::size_t)];
*reinterpret_cast<std::size_t*>(data) = length;
memcpy(data + sizeof(std::size_t), ostream.data(), length);
gtk_clipboard_set_with_data (clipboard, clipboard_targets, 1, clipboard_get, clipboard_clear, data);
}
ClipboardPasteFunc g_clipboardPasteFunc = 0;
void clipboard_paste(ClipboardPasteFunc paste)
{
GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
g_clipboardPasteFunc = paste;
gtk_clipboard_request_contents (clipboard, gdk_atom_intern(clipboard_targets[0].target, FALSE), clipboard_received, &g_clipboardPasteFunc);
}
#elif defined(WIN32)
const char* c_clipboard_format = "RadiantClippings";
#include <windows.h>
void clipboard_copy(ClipboardCopyFunc copy)
{
BufferOutputStream ostream;
copy(ostream);
bool bClipped = false;
UINT nClipboard = ::RegisterClipboardFormat(c_clipboard_format);
if (nClipboard > 0)
{
if (::OpenClipboard(0))
{
EmptyClipboard();
std::size_t length = ostream.size();
HANDLE h = ::GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, length + sizeof(std::size_t));
if (h != 0)
{
char *buffer = reinterpret_cast<char*>(::GlobalLock(h));
*reinterpret_cast<std::size_t*>(buffer) = length;
buffer += sizeof(std::size_t);
memcpy(buffer, ostream.data(), length);
::GlobalUnlock(h);
::SetClipboardData(nClipboard, h);
::CloseClipboard();
bClipped = true;
}
}
}
if (!bClipped)
{
globalOutputStream() << "Unable to register Windows clipboard formats, copy/paste between editors will not be possible\n";
}
}
void clipboard_paste(ClipboardPasteFunc paste)
{
UINT nClipboard = ::RegisterClipboardFormat(c_clipboard_format);
if (nClipboard > 0 && ::OpenClipboard(0))
{
if(IsClipboardFormatAvailable(nClipboard))
{
HANDLE h = ::GetClipboardData(nClipboard);
if(h)
{
const char *buffer = reinterpret_cast<const char*>(::GlobalLock(h));
std::size_t length = *reinterpret_cast<const std::size_t*>(buffer);
buffer += sizeof(std::size_t);
BufferInputStream istream(buffer, length);
paste(istream);
::GlobalUnlock(h);
}
}
::CloseClipboard();
}
}
#endif

View File

@ -0,0 +1,13 @@
#if !defined(INCLUDED_GTKUTIL_CLIPBOARD_H)
#define INCLUDED_GTKUTIL_CLIPBOARD_H
class TextOutputStream;
typedef void(*ClipboardCopyFunc)(TextOutputStream&);
void clipboard_copy(ClipboardCopyFunc copy);
class TextInputStream;
typedef void(*ClipboardPasteFunc)(TextInputStream&);
void clipboard_paste(ClipboardPasteFunc paste);
#endif

View File

@ -0,0 +1,3 @@
#include "closure.h"

View File

@ -0,0 +1,57 @@
#if !defined(INCLUDED_GTKUTIL_CLOSURE_H)
#define INCLUDED_GTKUTIL_CLOSURE_H
#include <glib-object.h>
#include "generic/callback.h"
inline void closure_destroy(gpointer data, GClosure* closure)
{
delete reinterpret_cast<Callback*>(data);
}
inline GClosure* create_cclosure(GCallback func, const Callback& callback)
{
return g_cclosure_new(func, new Callback(callback), closure_destroy);
}
inline GValue GValue_default()
{
GValue value;
value.g_type = 0;
return value;
}
inline gint object_get_int_property(GObject* object, const char* property)
{
GValue gvalue = GValue_default();
g_value_init(&gvalue, G_TYPE_INT);
g_object_get_property(object, property, &gvalue);
return g_value_get_int(&gvalue);
}
inline void object_set_int_property(GObject* object, const char* property, gint value)
{
GValue gvalue = GValue_default();
g_value_init(&gvalue, G_TYPE_INT);
g_value_set_int(&gvalue, value);
g_object_set_property(object, property, &gvalue);
}
inline gboolean object_get_boolean_property(GObject* object, const char* property)
{
GValue gvalue = GValue_default();
g_value_init(&gvalue, G_TYPE_BOOLEAN);
g_object_get_property(object, property, &gvalue);
return g_value_get_boolean(&gvalue);
}
inline void object_set_boolean_property(GObject* object, const char* property, gboolean value)
{
GValue gvalue = GValue_default();
g_value_init(&gvalue, G_TYPE_BOOLEAN);
g_value_set_boolean(&gvalue, value);
g_object_set_property(object, property, &gvalue);
}
#endif

View File

@ -0,0 +1,3 @@
#include "container.h"

View File

@ -0,0 +1,23 @@
#if !defined(INCLUDED_GTKUTIL_CONTAINER_H)
#define INCLUDED_GTKUTIL_CONTAINER_H
#include <gtk/gtkcontainer.h>
inline GtkWidget* container_add_widget(GtkContainer* container, GtkWidget* widget)
{
gtk_container_add(container, widget);
return widget;
}
inline void container_remove(GtkWidget* item, gpointer data)
{
gtk_container_remove(GTK_CONTAINER(data), item);
}
inline void container_remove_all(GtkContainer* container)
{
gtk_container_foreach(container, container_remove, container);
}
#endif

View File

@ -0,0 +1,71 @@
#include "cursor.h"
#include <string.h>
#include <gdk/gdkcursor.h>
#include <gdk/gdkpixmap.h>
GdkCursor* create_blank_cursor()
{
GdkPixmap *pixmap;
GdkBitmap *mask;
char buffer [(32 * 32)/8];
memset (buffer, 0, (32 * 32)/8);
GdkColor white = {0, 0xffff, 0xffff, 0xffff};
GdkColor black = {0, 0x0000, 0x0000, 0x0000};
pixmap = gdk_bitmap_create_from_data(0, buffer, 32, 32);
mask = gdk_bitmap_create_from_data(0, buffer, 32, 32);
GdkCursor *cursor = gdk_cursor_new_from_pixmap(pixmap, mask, &white, &black, 1, 1);
gdk_drawable_unref(pixmap);
gdk_drawable_unref(mask);
return cursor;
}
void blank_cursor(GtkWidget* widget)
{
GdkCursor* cursor = create_blank_cursor();
gdk_window_set_cursor (widget->window, cursor);
gdk_cursor_unref(cursor);
}
void default_cursor(GtkWidget* widget)
{
gdk_window_set_cursor(widget->window, 0);
}
#if defined(WIN32)
#include <gdk/gdkwin32.h>
void Sys_GetCursorPos (int *x, int *y)
{
POINT pos;
GetCursorPos(&pos);
*x = pos.x;
*y = pos.y;
}
void Sys_SetCursorPos (int x, int y)
{
SetCursorPos (x, y);
}
#else
#include <gdk/gdkx.h>
void Sys_GetCursorPos (int *x, int *y)
{
gdk_display_get_pointer(gdk_display_get_default(), 0, x, y, 0);
}
void Sys_SetCursorPos (int x, int y)
{
XWarpPointer (GDK_DISPLAY(), None, GDK_ROOT_WINDOW(), 0, 0, 0, 0, x, y);
}
#endif

View File

@ -0,0 +1,173 @@
#if !defined(INCLUDED_GTKUTIL_CURSOR_H)
#define INCLUDED_GTKUTIL_CURSOR_H
#include <glib/gmain.h>
#include <gdk/gdkevents.h>
#include <gtk/gtkwidget.h>
#include "debugging/debugging.h"
typedef struct _GdkCursor GdkCursor;
typedef struct _GtkWidget GtkWidget;
GdkCursor* create_blank_cursor();
void blank_cursor(GtkWidget* widget);
void default_cursor(GtkWidget* widget);
void Sys_GetCursorPos (int *x, int *y);
void Sys_SetCursorPos (int x, int y);
class DeferredMotion
{
guint m_handler;
typedef void(*MotionFunction)(gdouble x, gdouble y, guint state, void* data);
MotionFunction m_function;
void* m_data;
gdouble m_x;
gdouble m_y;
guint m_state;
static gboolean deferred(DeferredMotion* self)
{
self->m_handler = 0;
self->m_function(self->m_x, self->m_y, self->m_state, self->m_data);
return FALSE;
}
public:
DeferredMotion(MotionFunction function, void* data) : m_handler(0), m_function(function), m_data(data)
{
}
void motion(gdouble x, gdouble y, guint state)
{
m_x = x;
m_y = y;
m_state = state;
if(m_handler == 0)
{
m_handler = g_idle_add((GSourceFunc)deferred, this);
}
}
static gboolean gtk_motion(GtkWidget *widget, GdkEventMotion *event, DeferredMotion* self)
{
self->motion(event->x, event->y, event->state);
return FALSE;
}
};
class DeferredMotionDelta
{
int m_delta_x;
int m_delta_y;
guint m_motion_handler;
typedef void (*MotionDeltaFunction)(int x, int y, void* data);
MotionDeltaFunction m_function;
void* m_data;
static gboolean deferred_motion(gpointer data)
{
reinterpret_cast<DeferredMotionDelta*>(data)->m_function(
reinterpret_cast<DeferredMotionDelta*>(data)->m_delta_x,
reinterpret_cast<DeferredMotionDelta*>(data)->m_delta_y,
reinterpret_cast<DeferredMotionDelta*>(data)->m_data
);
reinterpret_cast<DeferredMotionDelta*>(data)->m_motion_handler = 0;
reinterpret_cast<DeferredMotionDelta*>(data)->m_delta_x = 0;
reinterpret_cast<DeferredMotionDelta*>(data)->m_delta_y = 0;
return FALSE;
}
public:
DeferredMotionDelta(MotionDeltaFunction function, void* data) : m_delta_x(0), m_delta_y(0), m_motion_handler(0), m_function(function), m_data(data)
{
}
void flush()
{
if(m_motion_handler != 0)
{
g_source_remove(m_motion_handler);
deferred_motion(this);
}
}
void motion_delta(int x, int y, unsigned int state)
{
m_delta_x += x;
m_delta_y += y;
if(m_motion_handler == 0)
{
m_motion_handler = g_idle_add(deferred_motion, this);
}
}
};
class FreezePointer
{
unsigned int handle_motion;
int recorded_x, recorded_y;
typedef void (*MotionDeltaFunction)(int x, int y, unsigned int state, void* data);
MotionDeltaFunction m_function;
void* m_data;
public:
FreezePointer() : handle_motion(0), m_function(0), m_data(0)
{
}
static gboolean motion_delta(GtkWidget *widget, GdkEventMotion *event, FreezePointer* self)
{
int current_x, current_y;
Sys_GetCursorPos(&current_x, &current_y);
int dx = current_x - self->recorded_x;
int dy = current_y - self->recorded_y;
if(dx != 0 || dy != 0)
{
//globalOutputStream() << "motion x: " << dx << ", y: " << dy << "\n";
Sys_SetCursorPos(self->recorded_x, self->recorded_y);
self->m_function(dx, dy, event->state, self->m_data);
}
return FALSE;
}
void freeze_pointer(GtkWidget* window, MotionDeltaFunction function, void* data)
{
ASSERT_MESSAGE(m_function == 0, "can't freeze pointer");
blank_cursor(window);
const GdkEventMask mask = static_cast<GdkEventMask>(GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK
| GDK_BUTTON_MOTION_MASK
| GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON2_MOTION_MASK
| GDK_BUTTON3_MOTION_MASK
| GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
| GDK_VISIBILITY_NOTIFY_MASK);
//GdkGrabStatus status =
gdk_pointer_grab(window->window, TRUE, mask, window->window, 0, GDK_CURRENT_TIME);
Sys_GetCursorPos(&recorded_x, &recorded_y);
Sys_SetCursorPos(recorded_x, recorded_y);
m_function = function;
m_data = data;
handle_motion = g_signal_connect(G_OBJECT(window), "motion_notify_event", G_CALLBACK(motion_delta), this);
}
void unfreeze_pointer(GtkWidget* window)
{
g_signal_handler_disconnect(G_OBJECT(window), handle_motion);
m_function = 0;
m_data = 0;
Sys_SetCursorPos(recorded_x, recorded_y);
gdk_pointer_ungrab(GDK_CURRENT_TIME);
default_cursor(window);
}
};
#endif

View File

@ -0,0 +1,283 @@
#include "dialog.h"
#include <gtk/gtkmain.h>
#include <gtk/gtkalignment.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtkradiobutton.h>
#include <gtk/gtkframe.h>
#include <gtk/gtktable.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkbutton.h>
#include <gtk/gtklabel.h>
#include "button.h"
#include "window.h"
GtkVBox* create_dialog_vbox(int spacing, int border)
{
GtkVBox* vbox = GTK_VBOX(gtk_vbox_new(FALSE, spacing));
gtk_widget_show(GTK_WIDGET(vbox));
gtk_container_set_border_width(GTK_CONTAINER(vbox), border);
return vbox;
}
GtkHBox* create_dialog_hbox(int spacing, int border)
{
GtkHBox* hbox = GTK_HBOX(gtk_hbox_new(FALSE, spacing));
gtk_widget_show(GTK_WIDGET(hbox));
gtk_container_set_border_width(GTK_CONTAINER(hbox), border);
return hbox;
}
GtkFrame* create_dialog_frame(const char* label, GtkShadowType shadow)
{
GtkFrame* frame = GTK_FRAME(gtk_frame_new(label));
gtk_widget_show(GTK_WIDGET(frame));
gtk_frame_set_shadow_type(frame, shadow);
return frame;
}
GtkTable* create_dialog_table(unsigned int rows, unsigned int columns, unsigned int row_spacing, unsigned int col_spacing, int border)
{
GtkTable* table = GTK_TABLE(gtk_table_new(rows, columns, FALSE));
gtk_widget_show(GTK_WIDGET(table));
gtk_table_set_row_spacings(table, row_spacing);
gtk_table_set_col_spacings(table, col_spacing);
gtk_container_set_border_width(GTK_CONTAINER(table), border);
return table;
}
GtkButton* create_dialog_button(const char* label, GCallback func, gpointer data)
{
GtkButton* button = GTK_BUTTON(gtk_button_new_with_label(label));
gtk_widget_set_size_request(GTK_WIDGET(button), 64, -1);
gtk_widget_show(GTK_WIDGET(button));
g_signal_connect(G_OBJECT(button), "clicked", func, data);
return button;
}
GtkWindow* create_dialog_window(GtkWindow* parent, const char* title, GCallback func, gpointer data, int default_w, int default_h)
{
GtkWindow* window = create_floating_window(title, parent);
gtk_window_set_default_size(window, default_w, default_h);
gtk_window_set_position(window, GTK_WIN_POS_CENTER_ON_PARENT);
g_signal_connect(G_OBJECT(window), "delete_event", func, data);
return window;
}
gboolean modal_dialog_button_clicked(GtkWidget *widget, ModalDialogButton* button)
{
button->m_dialog.loop = false;
button->m_dialog.ret = button->m_value;
return TRUE;
}
gboolean modal_dialog_delete(GtkWidget *widget, GdkEvent* event, ModalDialog* dialog)
{
dialog->loop = 0;
dialog->ret = eIDCANCEL;
return TRUE;
}
EMessageBoxReturn modal_dialog_show(GtkWindow* window, ModalDialog& dialog)
{
gtk_grab_add(GTK_WIDGET(window));
gtk_widget_show(GTK_WIDGET(window));
dialog.loop = true;
while(dialog.loop)
{
gtk_main_iteration();
}
gtk_widget_hide(GTK_WIDGET(window));
gtk_grab_remove(GTK_WIDGET(window));
return dialog.ret;
}
GtkButton* create_modal_dialog_button(const char* label, ModalDialogButton& button)
{
return create_dialog_button(label, G_CALLBACK(modal_dialog_button_clicked), &button);
}
GtkWindow* create_modal_dialog_window(GtkWindow* parent, const char* title, ModalDialog& dialog, int default_w, int default_h)
{
return create_dialog_window(parent, title, G_CALLBACK(modal_dialog_delete), &dialog, default_w, default_h);
}
GtkWindow* create_fixedsize_modal_dialog_window(GtkWindow* parent, const char* title, ModalDialog& dialog, int width, int height)
{
GtkWindow* window = create_modal_dialog_window(parent, title, dialog, width, height);
gtk_window_set_resizable(window, FALSE);
gtk_window_set_modal(window, TRUE);
gtk_window_set_position(window, GTK_WIN_POS_CENTER);
window_remove_minmax(window);
//gtk_widget_set_size_request(GTK_WIDGET(window), width, height);
//gtk_window_set_default_size(window, width, height);
//gtk_window_resize(window, width, height);
//GdkGeometry geometry = { width, height, -1, -1, width, height, -1, -1, -1, -1, GDK_GRAVITY_STATIC, };
//gtk_window_set_geometry_hints(window, GTK_WIDGET(window), &geometry, (GdkWindowHints)(GDK_HINT_POS|GDK_HINT_MIN_SIZE|GDK_HINT_BASE_SIZE));
return window;
}
gboolean dialog_button_ok(GtkWidget *widget, ModalDialog* data)
{
data->loop = false;
data->ret = eIDOK;
return TRUE;
}
gboolean dialog_button_cancel(GtkWidget *widget, ModalDialog* data)
{
data->loop = false;
data->ret = eIDCANCEL;
return TRUE;
}
gboolean dialog_button_yes(GtkWidget *widget, ModalDialog* data)
{
data->loop = false;
data->ret = eIDYES;
return TRUE;
}
gboolean dialog_button_no(GtkWidget *widget, ModalDialog* data)
{
data->loop = false;
data->ret = eIDNO;
return TRUE;
}
gboolean dialog_delete_callback(GtkWidget *widget, GdkEventAny* event, ModalDialog* data)
{
gtk_widget_hide(widget);
data->loop = false;
return TRUE;
}
GtkWindow* create_simple_modal_dialog_window(const char* title, ModalDialog& dialog, GtkWidget* contents)
{
GtkWindow* window = create_fixedsize_modal_dialog_window(0, title, dialog);
GtkVBox* vbox1 = create_dialog_vbox(8, 4);
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox1));
gtk_container_add(GTK_CONTAINER(vbox1), contents);
GtkAlignment* alignment = GTK_ALIGNMENT(gtk_alignment_new(0.5, 0.0, 0.0, 0.0));
gtk_widget_show(GTK_WIDGET(alignment));
gtk_box_pack_start(GTK_BOX(vbox1), GTK_WIDGET(alignment), FALSE, FALSE, 0);
GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &dialog);
gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(button));
return window;
}
RadioHBox RadioHBox_new(StringArrayRange names)
{
GtkHBox* hbox = GTK_HBOX(gtk_hbox_new(TRUE, 4));
gtk_widget_show(GTK_WIDGET(hbox));
GSList* group = 0;
GtkRadioButton* radio = 0;
for(StringArrayRange::Iterator i = names.begin; i != names.end; ++i)
{
radio = GTK_RADIO_BUTTON(gtk_radio_button_new_with_label(group, *i));
gtk_widget_show(GTK_WIDGET(radio));
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(radio), FALSE, FALSE, 0);
group = gtk_radio_button_get_group(radio);
}
return RadioHBox(hbox, radio);
}
PathEntry PathEntry_new()
{
GtkFrame* frame = GTK_FRAME(gtk_frame_new(NULL));
gtk_widget_show(GTK_WIDGET(frame));
gtk_frame_set_shadow_type(frame, GTK_SHADOW_IN);
// path entry
GtkHBox* hbox = GTK_HBOX(gtk_hbox_new(FALSE, 0));
gtk_widget_show(GTK_WIDGET(hbox));
GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
gtk_entry_set_has_frame(entry, FALSE);
gtk_widget_show(GTK_WIDGET(entry));
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(entry), TRUE, TRUE, 0);
// browse button
GtkButton* button = GTK_BUTTON(gtk_button_new());
button_set_icon(button, "ellipsis.bmp");
gtk_widget_show(GTK_WIDGET(button));
gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(hbox));
return PathEntry(frame, entry, button);
}
void PathEntry_setPath(PathEntry& self, const char* path)
{
gtk_entry_set_text(self.m_entry, path);
}
typedef ReferenceCaller1<PathEntry, const char*, PathEntry_setPath> PathEntrySetPathCaller;
void BrowsedPathEntry_clicked(GtkWidget* widget, BrowsedPathEntry* self)
{
self->m_browse(PathEntrySetPathCaller(self->m_entry));
}
BrowsedPathEntry::BrowsedPathEntry(const BrowseCallback& browse) :
m_entry(PathEntry_new()),
m_browse(browse)
{
g_signal_connect(G_OBJECT(m_entry.m_button), "clicked", G_CALLBACK(BrowsedPathEntry_clicked), this);
}
GtkLabel* DialogLabel_new(const char* name)
{
GtkLabel* label = GTK_LABEL(gtk_label_new(name));
gtk_widget_show(GTK_WIDGET(label));
gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
gtk_label_set_justify(label, GTK_JUSTIFY_LEFT);
return label;
}
GtkTable* DialogRow_new(const char* name, GtkWidget* widget)
{
GtkTable* table = GTK_TABLE(gtk_table_new(1, 3, TRUE));
gtk_widget_show(GTK_WIDGET(table));
gtk_table_set_col_spacings(table, 4);
gtk_table_set_row_spacings(table, 0);
gtk_table_attach(table, GTK_WIDGET(DialogLabel_new(name)), 0, 1, 0, 1,
(GtkAttachOptions) (GTK_EXPAND|GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_table_attach(table, widget, 1, 3, 0, 1,
(GtkAttachOptions) (GTK_EXPAND|GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
return table;
}
void DialogVBox_packRow(GtkVBox* vbox, GtkWidget* row)
{
gtk_box_pack_start(GTK_BOX(vbox), row, FALSE, FALSE, 0);
}

View File

@ -0,0 +1,125 @@
#if !defined(INCLUDED_GTKUTIL_DIALOG_H)
#define INCLUDED_GTKUTIL_DIALOG_H
#include "generic/callback.h"
#include "generic/arrayrange.h"
#include "qerplugin.h"
#include <gtk/gtkenums.h>
typedef int gint;
typedef gint gboolean;
typedef struct _GdkEventAny GdkEventAny;
typedef struct _GtkWidget GtkWidget;
typedef struct _GtkHBox GtkHBox;
typedef struct _GtkVBox GtkVBox;
typedef struct _GtkRadioButton GtkRadioButton;
typedef struct _GtkFrame GtkFrame;
typedef struct _GtkEntry GtkEntry;
typedef struct _GtkButton GtkButton;
typedef struct _GtkLabel GtkLabel;
typedef struct _GtkTable GtkTable;
struct ModalDialog
{
ModalDialog()
: loop(true), ret(eIDCANCEL)
{
}
bool loop;
EMessageBoxReturn ret;
};
struct ModalDialogButton
{
ModalDialogButton(ModalDialog& dialog, EMessageBoxReturn value)
: m_dialog(dialog), m_value(value)
{
}
ModalDialog& m_dialog;
EMessageBoxReturn m_value;
};
typedef void (*GCallback)(void);
typedef void* gpointer;
typedef struct _GtkWindow GtkWindow;
typedef struct _GtkTable GtkTable;
typedef struct _GtkButton GtkButton;
typedef struct _GtkVBox GtkVBox;
typedef struct _GtkHBox GtkHBox;
typedef struct _GtkFrame GtkFrame;
GtkWindow* create_fixedsize_modal_window(GtkWindow* parent, const char* title, int width, int height);
GtkWindow* create_dialog_window(GtkWindow* parent, const char* title, GCallback func, gpointer data, int default_w = -1, int default_h = -1);
GtkTable* create_dialog_table(unsigned int rows, unsigned int columns, unsigned int row_spacing, unsigned int col_spacing, int border = 0);
GtkButton* create_dialog_button(const char* label, GCallback func, gpointer data);
GtkVBox* create_dialog_vbox(int spacing, int border = 0);
GtkHBox* create_dialog_hbox(int spacing, int border = 0);
GtkFrame* create_dialog_frame(const char* label, GtkShadowType shadow = GTK_SHADOW_ETCHED_IN);
GtkButton* create_modal_dialog_button(const char* label, ModalDialogButton& button);
GtkWindow* create_modal_dialog_window(GtkWindow* parent, const char* title, ModalDialog& dialog, int default_w = -1, int default_h = -1);
GtkWindow* create_fixedsize_modal_dialog_window(GtkWindow* parent, const char* title, ModalDialog& dialog, int width = -1, int height = -1);
EMessageBoxReturn modal_dialog_show(GtkWindow* window, ModalDialog& dialog);
gboolean dialog_button_ok(GtkWidget *widget, ModalDialog* data);
gboolean dialog_button_cancel(GtkWidget *widget, ModalDialog* data);
gboolean dialog_button_yes(GtkWidget *widget, ModalDialog* data);
gboolean dialog_button_no(GtkWidget *widget, ModalDialog* data);
gboolean dialog_delete_callback(GtkWidget *widget, GdkEventAny* event, ModalDialog* data);
GtkWindow* create_simple_modal_dialog_window(const char* title, ModalDialog& dialog, GtkWidget* contents);
class RadioHBox
{
public:
GtkHBox* m_hbox;
GtkRadioButton* m_radio;
RadioHBox(GtkHBox* hbox, GtkRadioButton* radio) :
m_hbox(hbox),
m_radio(radio)
{
}
};
RadioHBox RadioHBox_new(StringArrayRange names);
class PathEntry
{
public:
GtkFrame* m_frame;
GtkEntry* m_entry;
GtkButton* m_button;
PathEntry(GtkFrame* frame, GtkEntry* entry, GtkButton* button) :
m_frame(frame),
m_entry(entry),
m_button(button)
{
}
};
PathEntry PathEntry_new();
class BrowsedPathEntry
{
public:
typedef Callback1<const char*> SetPathCallback;
typedef Callback1<const SetPathCallback&> BrowseCallback;
PathEntry m_entry;
BrowseCallback m_browse;
BrowsedPathEntry(const BrowseCallback& browse);
};
GtkLabel* DialogLabel_new(const char* name);
GtkTable* DialogRow_new(const char* name, GtkWidget* widget);
typedef struct _GtkVBox GtkVBox;
void DialogVBox_packRow(GtkVBox* vbox, GtkWidget* row);
#endif

View File

@ -0,0 +1,3 @@
#include "entry.h"

View File

@ -0,0 +1,43 @@
#if !defined(INCLUDED_GTKUTIL_ENTRY_H)
#define INCLUDED_GTKUTIL_ENTRY_H
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtkentry.h>
inline void entry_set_string(GtkEntry* entry, const char* string)
{
gtk_entry_set_text(entry, string);
}
inline void entry_set_int(GtkEntry* entry, int i)
{
char buf[32];
sprintf(buf, "%d", i);
entry_set_string(entry, buf);
}
inline void entry_set_float(GtkEntry* entry, float f)
{
char buf[32];
sprintf(buf, "%g", f);
entry_set_string(entry, buf);
}
inline const char* entry_get_string(GtkEntry* entry)
{
return gtk_entry_get_text(entry);
}
inline int entry_get_int(GtkEntry* entry)
{
return atoi(entry_get_string(entry));
}
inline double entry_get_float(GtkEntry* entry)
{
return atof(entry_get_string(entry));
}
#endif

View File

@ -0,0 +1,463 @@
#include "filechooser.h"
#include "ifiletypes.h"
#include <list>
#include <vector>
#include <gtk/gtkwidget.h>
#include <gtk/gtkwindow.h>
#include <gtk/gtkfilechooser.h>
#include <gtk/gtkfilechooserdialog.h>
#include <gtk/gtkstock.h>
#include "string/string.h"
#include "stream/stringstream.h"
#include "container/array.h"
#include "os/path.h"
#include "os/file.h"
#include "messagebox.h"
struct filetype_pair_t
{
filetype_pair_t()
: m_moduleName("")
{
}
filetype_pair_t(const char* moduleName, filetype_t type)
: m_moduleName(moduleName), m_type(type)
{
}
const char* m_moduleName;
filetype_t m_type;
};
class FileTypeList : public IFileTypeList
{
struct filetype_copy_t
{
filetype_copy_t(const filetype_pair_t& other)
: m_moduleName(other.m_moduleName), m_name(other.m_type.name), m_pattern(other.m_type.pattern)
{
}
CopiedString m_moduleName;
CopiedString m_name;
CopiedString m_pattern;
};
typedef std::list<filetype_copy_t> Types;
Types m_types;
public:
typedef Types::const_iterator const_iterator;
const_iterator begin() const
{
return m_types.begin();
}
const_iterator end() const
{
return m_types.end();
}
std::size_t size() const
{
return m_types.size();
}
void addType(const char* moduleName, filetype_t type)
{
m_types.push_back(filetype_pair_t(moduleName, type));
}
};
#ifdef WIN32
class Win32Filters
{
const FileTypeList& m_types;
Array<char> m_filters;
public:
Win32Filters(const FileTypeList& typeList) : m_types(typeList)
{
std::size_t len = 0;
for(FileTypeList::const_iterator i = m_types.begin(); i != m_types.end(); ++i)
{
len = len + strlen((*i).m_name.c_str()) + strlen((*i).m_pattern.c_str()) * 2 + 5;
}
m_filters.resize(len + 1); // length + null char
char *w = m_filters.data();
for(FileTypeList::const_iterator i = m_types.begin(); i != m_types.end(); ++i)
{
for(const char *r = (*i).m_name.c_str(); *r!='\0'; r++, w++)
{
*w = *r;
}
*w++ = ' ';
*w++ = '(';
for(const char *r = (*i).m_pattern.c_str(); *r!='\0'; r++, w++)
{
*w = *r;
}
*w++ = ')';
*w++ = '\0';
for(const char *r = (*i).m_pattern.c_str(); *r!='\0'; r++, w++)
{
*w = (*r == ',') ? ';' : *r;
}
*w++ = '\0';
}
m_filters[len] = '\0';
}
filetype_pair_t getType(const char *filter) const
{
for(FileTypeList::const_iterator i = m_types.begin(); i != m_types.end(); ++i)
{
if(string_equal((*i).m_pattern.c_str(), filter))
{
return filetype_pair_t((*i).m_moduleName.c_str(), filetype_t((*i).m_name.c_str(), (*i).m_pattern.c_str()));
}
}
return filetype_pair_t();
}
const char* getFilters() const
{
return m_filters.data();
}
};
#define WIN32_LEAN_AND_MEAN
#include <gdk/gdkwin32.h>
#include <commdlg.h>
static char szFile[MAX_PATH]; /* filename string */
#define FILEDLG_CUSTOM_FILTER_LENGTH 64
// to be used with the advanced file selector
const char* file_dialog_show_win32(GtkWidget* parent, bool open, const char* title, const char* path, const char* pattern)
{
const char* r;
char* w;
filetype_t type;
FileTypeList typelist;
if(pattern == 0)
{
pattern = "*";
}
GlobalFiletypes().getTypeList(pattern, &typelist);
Win32Filters filters(typelist);
// win32 dialog stores the selected "save as type" extension in the second null-terminated string
char customfilter[FILEDLG_CUSTOM_FILTER_LENGTH];
static OPENFILENAME ofn; /* common dialog box structure */
static char szDirName[MAX_PATH]; /* directory string */
static char szFile[MAX_PATH]; /* filename string */
static char szFileTitle[MAX_PATH]; /* file title string */
static int i, cbString; /* integer count variables */
static HANDLE hf; /* file handle */
// do that the native way
/* Place the terminating null character in the szFile. */
szFile[0] = '\0';
customfilter[0] = customfilter[1] = customfilter[2] = '\0';
/* Set the members of the OPENFILENAME structure. */
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = (HWND)GDK_WINDOW_HWND(parent->window);
ofn.nFilterIndex = 0;
ofn.lpstrFilter = filters.getFilters();
ofn.lpstrCustomFilter = customfilter;
ofn.nMaxCustFilter = sizeof(customfilter);
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFileTitle = 0; // we don't need to get the name of the file
if(path)
{
// szDirName: Radiant uses unix convention for paths internally
// Win32 (of course) and Gtk (who would have thought) expect the '\\' convention
// copy path, replacing dir separators as appropriate
for(r=path, w=szDirName; *r!='\0'; r++)
*w++ = (*r=='/') ? '\\' : *r;
// terminate string
*w = '\0';
ofn.lpstrInitialDir = szDirName;
}
else ofn.lpstrInitialDir = 0;
ofn.lpstrTitle = title;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
/* Display the Open dialog box. */
// it's open or close depending on 'open' parameter
if (open)
{
if (!GetOpenFileName(&ofn))
return 0; // canceled
}
else
{
if (!GetSaveFileName(&ofn))
return 0; // canceled
}
if(!string_equal(pattern, "*"))
{
type = filters.getType(customfilter+1).m_type;
}
// don't return an empty filename
if(szFile[0] == '\0') return 0;
// convert back to unix format
for(w=szFile; *w!='\0'; w++)
{
if(*w=='\\')
{
*w = '/';
}
}
// when saving, force an extension depending on filetype
/* \todo SPoG - file_dialog should return filetype information separately.. not force file extension.. */
if(!open && !string_equal(pattern, "*"))
{
// last ext separator
const char* extension = path_get_extension(szFile);
// no extension
if(string_empty(extension))
{
strcat(szFile, type.pattern+1);
}
else
{
strcpy(szFile + (extension - szFile), type.pattern+2);
}
}
return szFile;
}
#endif
class GTKMasks
{
const FileTypeList& m_types;
public:
std::vector<CopiedString> m_filters;
std::vector<CopiedString> m_masks;
GTKMasks(const FileTypeList& types) : m_types(types)
{
m_masks.reserve(m_types.size());
for(FileTypeList::const_iterator i = m_types.begin(); i != m_types.end(); ++i)
{
std::size_t len = strlen((*i).m_name.c_str()) + strlen((*i).m_pattern.c_str()) + 3;
StringOutputStream buffer(len + 1); // length + null char
buffer << (*i).m_name.c_str() << " <" << (*i).m_pattern.c_str() << ">";
m_masks.push_back(buffer.c_str());
}
m_filters.reserve(m_types.size());
for(FileTypeList::const_iterator i = m_types.begin(); i != m_types.end(); ++i)
{
m_filters.push_back((*i).m_pattern);
}
}
filetype_pair_t GetTypeForGTKMask(const char *mask) const
{
std::vector<CopiedString>::const_iterator j = m_masks.begin();
for(FileTypeList::const_iterator i = m_types.begin(); i != m_types.end(); ++i, ++j)
{
if(string_equal((*j).c_str(), mask))
{
return filetype_pair_t((*i).m_moduleName.c_str(), filetype_t((*i).m_name.c_str(), (*i).m_pattern.c_str()));
}
}
return filetype_pair_t();
}
};
static char g_file_dialog_file[1024];
const char* file_dialog_show(GtkWidget* parent, bool open, const char* title, const char* path, const char* pattern)
{
filetype_t type;
if(pattern == 0)
{
pattern = "*";
}
FileTypeList typelist;
GlobalFiletypes().getTypeList(pattern, &typelist);
GTKMasks masks(typelist);
if (title == 0)
title = open ? "Open File" : "Save File";
GtkWidget* dialog;
if (open)
{
dialog = gtk_file_chooser_dialog_new(title,
GTK_WINDOW(parent),
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL);
}
else
{
dialog = gtk_file_chooser_dialog_new(title,
GTK_WINDOW(parent),
GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "unnamed");
}
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
// we expect an actual path below, if the path is 0 we might crash
if (path != 0 && !string_empty(path))
{
ASSERT_MESSAGE(path_is_absolute(path), "file_dialog_show: path not absolute: " << makeQuoted(path));
Array<char> new_path(strlen(path)+1);
// copy path, replacing dir separators as appropriate
Array<char>::iterator w = new_path.begin();
for(const char* r = path; *r != '\0'; ++r)
{
*w++ = (*r == '/') ? G_DIR_SEPARATOR : *r;
}
// remove separator from end of path if required
if(*(w-1) == G_DIR_SEPARATOR)
{
--w;
}
// terminate string
*w = '\0';
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), new_path.data());
}
// we should add all important paths as shortcut folder...
// gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(dialog), "/tmp/", NULL);
for(std::size_t i = 0; i < masks.m_filters.size(); ++i)
{
GtkFileFilter* filter = gtk_file_filter_new();
gtk_file_filter_add_pattern(filter, masks.m_filters[i].c_str());
gtk_file_filter_set_name(filter, masks.m_masks[i].c_str());
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
}
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
{
strcpy(g_file_dialog_file, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)));
if(!string_equal(pattern, "*"))
{
GtkFileFilter* filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog));
type = masks.GetTypeForGTKMask(gtk_file_filter_get_name(filter)).m_type;
// last ext separator
const char* extension = path_get_extension(g_file_dialog_file);
// no extension
if(string_empty(extension))
{
strcat(g_file_dialog_file, type.pattern+1);
}
else
{
strcpy(g_file_dialog_file + (extension - g_file_dialog_file), type.pattern+2);
}
}
// convert back to unix format
for(char* w = g_file_dialog_file; *w!='\0'; w++)
{
if(*w=='\\')
{
*w = '/';
}
}
}
else
{
g_file_dialog_file[0] = '\0';
}
gtk_widget_destroy(dialog);
// don't return an empty filename
if(g_file_dialog_file[0] == '\0') return NULL;
return g_file_dialog_file;
}
char* dir_dialog(GtkWidget* parent, const char* title, const char* path)
{
GtkWidget* dialog = gtk_file_chooser_dialog_new(title,
GTK_WINDOW(parent),
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL);
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
if(!string_empty(path))
{
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
}
char* filename = 0;
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
{
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
}
gtk_widget_destroy(dialog);
return filename;
}
#ifdef WIN32
bool g_FileChooser_nativeGUI = true;
#endif
const char* file_dialog (GtkWidget* parent, bool open, const char* title, const char* path, const char* pattern)
{
for(;;)
{
const char* file =
#ifdef WIN32
g_FileChooser_nativeGUI
? file_dialog_show_win32(parent, open, title, path, pattern) :
#endif
file_dialog_show(parent, open, title, path, pattern);
if(open
|| !file_exists(file)
|| gtk_MessageBox(parent, "The file specified already exists.\nDo you want to replace it?", title, eMB_NOYES, eMB_ICONQUESTION) == eIDYES)
{
return file;
}
}
}

View File

@ -0,0 +1,22 @@
#if !defined(INCLUDED_GTKUTIL_FILECHOOSER_H)
#define INCLUDED_GTKUTIL_FILECHOOSER_H
/// \file
/// GTK+ file-chooser dialogs.
#ifdef WIN32
extern bool g_FileChooser_nativeGUI;
#endif
typedef struct _GtkWidget GtkWidget;
const char* file_dialog(GtkWidget *parent, bool open, const char* title, const char* path = 0, const char* pattern = 0);
/// \brief Prompts the user to browse for a directory.
/// The prompt window will be transient to \p parent.
/// The directory will initially default to \p path, which must be an absolute path.
/// The returned string is allocated with \c g_malloc and must be freed with \c g_free.
char* dir_dialog(GtkWidget *parent, const char* title = "Choose Directory", const char* path = "");
#endif

View File

@ -0,0 +1,15 @@
#include "frame.h"
#include <gtk/gtkframe.h>
GtkFrame* create_framed_widget(GtkWidget* widget)
{
GtkFrame* frame = GTK_FRAME(gtk_frame_new(0));
gtk_widget_show(GTK_WIDGET(frame));
gtk_frame_set_shadow_type(frame, GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER(frame), widget);
gtk_widget_show(GTK_WIDGET(widget));
return frame;
}

View File

@ -0,0 +1,9 @@
#if !defined(INCLUDED_GTKUTIL_FRAME_H)
#define INCLUDED_GTKUTIL_FRAME_H
typedef struct _GtkWidget GtkWidget;
typedef struct _GtkFrame GtkFrame;
GtkFrame* create_framed_widget(GtkWidget* widget);
#endif

View File

@ -0,0 +1,36 @@
#include "glfont.h"
#include "igl.h"
#include <gtk/gtkglwidget.h>
GLFont glfont_create(const char* font_string)
{
GLuint font_list_base = glGenLists (256);
gint font_height = 0;
PangoFontDescription* font_desc = pango_font_description_from_string (font_string);
PangoFont* font = gdk_gl_font_use_pango_font (font_desc, 0, 256, font_list_base);
if(font != 0)
{
PangoFontMetrics* font_metrics = pango_font_get_metrics (font, 0);
font_height = pango_font_metrics_get_ascent (font_metrics) +
pango_font_metrics_get_descent (font_metrics);
font_height = PANGO_PIXELS (font_height);
pango_font_metrics_unref (font_metrics);
}
pango_font_description_free (font_desc);
return GLFont(font_list_base, font_height);
}
void glfont_release(GLFont& font)
{
glDeleteLists(font.getDisplayList(), 256);
font = GLFont(0, 0);
}

View File

@ -0,0 +1,28 @@
#if !defined(INCLUDED_GTKUTIL_GLFONT_H)
#define INCLUDED_GTKUTIL_GLFONT_H
typedef unsigned int GLuint;
class GLFont
{
GLuint m_displayList;
int m_pixelHeight;
public:
GLFont(GLuint displayList, int pixelHeight) : m_displayList(displayList), m_pixelHeight(pixelHeight)
{
}
GLuint getDisplayList() const
{
return m_displayList;
}
int getPixelHeight() const
{
return m_pixelHeight;
}
};
GLFont glfont_create(const char* font_string);
void glfont_release(GLFont& font);
#endif

View File

@ -0,0 +1,254 @@
// OpenGL widget based on GtkGLExt
#include "glwidget.h"
#include "debugging/debugging.h"
#include "igl.h"
#include <gtk/gtkdrawingarea.h>
#include <gtk/gtkglwidget.h>
#include "pointer.h"
void (*GLWidget_sharedContextCreated)() = 0;
void (*GLWidget_sharedContextDestroyed)() = 0;
typedef int* attribs_t;
struct config_t
{
const char* name;
attribs_t attribs;
};
typedef const config_t* configs_iterator;
int config_rgba32[] = {
GDK_GL_RGBA,
GDK_GL_DOUBLEBUFFER,
GDK_GL_BUFFER_SIZE, 24,
GDK_GL_ATTRIB_LIST_NONE,
};
int config_rgba[] = {
GDK_GL_RGBA,
GDK_GL_DOUBLEBUFFER,
GDK_GL_BUFFER_SIZE, 16,
GDK_GL_ATTRIB_LIST_NONE,
};
const config_t configs[] = {
{
"colour-buffer = 32bpp, depth-buffer = none",
config_rgba32,
},
{
"colour-buffer = 16bpp, depth-buffer = none",
config_rgba,
}
};
GdkGLConfig* glconfig_new()
{
GdkGLConfig* glconfig = 0;
for(configs_iterator i = configs, end = configs + 2; i != end; ++i)
{
glconfig = gdk_gl_config_new((*i).attribs);
if(glconfig != 0)
{
globalOutputStream() << "OpenGL window configuration: " << (*i).name << "\n";
return glconfig;
}
}
globalOutputStream() << "OpenGL window configuration: colour-buffer = auto, depth-buffer = none\n";
return gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGBA | GDK_GL_MODE_DOUBLE));
}
int config_rgba32_depth32[] = {
GDK_GL_RGBA,
GDK_GL_DOUBLEBUFFER,
GDK_GL_BUFFER_SIZE, 24,
GDK_GL_DEPTH_SIZE, 32,
GDK_GL_ATTRIB_LIST_NONE,
};
int config_rgba32_depth24[] = {
GDK_GL_RGBA,
GDK_GL_DOUBLEBUFFER,
GDK_GL_BUFFER_SIZE, 24,
GDK_GL_DEPTH_SIZE, 24,
GDK_GL_ATTRIB_LIST_NONE,
};
int config_rgba32_depth16[] = {
GDK_GL_RGBA,
GDK_GL_DOUBLEBUFFER,
GDK_GL_BUFFER_SIZE, 24,
GDK_GL_DEPTH_SIZE, 16,
GDK_GL_ATTRIB_LIST_NONE,
};
int config_rgba32_depth[] = {
GDK_GL_RGBA,
GDK_GL_DOUBLEBUFFER,
GDK_GL_BUFFER_SIZE, 24,
GDK_GL_DEPTH_SIZE, 1,
GDK_GL_ATTRIB_LIST_NONE,
};
int config_rgba_depth16[] = {
GDK_GL_RGBA,
GDK_GL_DOUBLEBUFFER,
GDK_GL_BUFFER_SIZE, 16,
GDK_GL_DEPTH_SIZE, 16,
GDK_GL_ATTRIB_LIST_NONE,
};
int config_rgba_depth[] = {
GDK_GL_RGBA,
GDK_GL_DOUBLEBUFFER,
GDK_GL_BUFFER_SIZE, 16,
GDK_GL_DEPTH_SIZE, 1,
GDK_GL_ATTRIB_LIST_NONE,
};
const config_t configs_with_depth[] =
{
{
"colour-buffer = 32bpp, depth-buffer = 32bpp",
config_rgba32_depth32,
},
{
"colour-buffer = 32bpp, depth-buffer = 24bpp",
config_rgba32_depth24,
},
{
"colour-buffer = 32bpp, depth-buffer = 16bpp",
config_rgba32_depth16,
},
{
"colour-buffer = 32bpp, depth-buffer = auto",
config_rgba32_depth,
},
{
"colour-buffer = 16bpp, depth-buffer = 16bpp",
config_rgba_depth16,
},
{
"colour-buffer = auto, depth-buffer = auto",
config_rgba_depth,
},
};
GdkGLConfig* glconfig_new_with_depth()
{
GdkGLConfig* glconfig = 0;
for(configs_iterator i = configs_with_depth, end = configs_with_depth + 6; i != end; ++i)
{
glconfig = gdk_gl_config_new((*i).attribs);
if(glconfig != 0)
{
globalOutputStream() << "OpenGL window configuration: " << (*i).name << "\n";
return glconfig;
}
}
globalOutputStream() << "OpenGL window configuration: colour-buffer = auto, depth-buffer = auto (fallback)\n";
return gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGBA | GDK_GL_MODE_DOUBLE | GDK_GL_MODE_DEPTH));
}
unsigned int g_context_count = 0;
namespace
{
GtkWidget* g_shared = 0;
}
gint glwidget_context_created(GtkWidget* widget, gpointer data)
{
if(++g_context_count == 1)
{
g_shared = widget;
gtk_widget_ref(g_shared);
glwidget_make_current(g_shared);
GlobalOpenGL().contextValid = true;
GLWidget_sharedContextCreated();
}
return FALSE;
}
gint glwidget_context_destroyed(GtkWidget* widget, gpointer data)
{
if(--g_context_count == 0)
{
GlobalOpenGL().contextValid = false;
GLWidget_sharedContextDestroyed();
gtk_widget_unref(g_shared);
g_shared = 0;
}
return FALSE;
}
gboolean glwidget_enable_gl(GtkWidget* widget, GtkWidget* widget2, gpointer data)
{
if(widget2 == 0 && !gtk_widget_is_gl_capable(widget))
{
GdkGLConfig* glconfig = (g_object_get_data(G_OBJECT(widget), "zbuffer")) ? glconfig_new_with_depth() : glconfig_new();
ASSERT_MESSAGE(glconfig != 0, "failed to create OpenGL config");
gtk_widget_set_gl_capability(widget, glconfig, g_shared != 0 ? gtk_widget_get_gl_context(g_shared) : 0, TRUE, GDK_GL_RGBA_TYPE);
gtk_widget_realize(widget);
if(g_shared == 0)
{
g_shared = widget;
}
// free glconfig?
}
return FALSE;
}
GtkWidget* glwidget_new(gboolean zbuffer)
{
GtkWidget* widget = gtk_drawing_area_new();
g_object_set_data(G_OBJECT(widget), "zbuffer", gint_to_pointer(zbuffer));
g_signal_connect(G_OBJECT(widget), "hierarchy-changed", G_CALLBACK(glwidget_enable_gl), 0);
g_signal_connect(G_OBJECT(widget), "realize", G_CALLBACK(glwidget_context_created), 0);
g_signal_connect(G_OBJECT(widget), "unrealize", G_CALLBACK(glwidget_context_destroyed), 0);
return widget;
}
void glwidget_destroy_context (GtkWidget *widget)
{
}
void glwidget_create_context (GtkWidget *widget)
{
}
void glwidget_swap_buffers (GtkWidget *widget)
{
GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
gdk_gl_drawable_swap_buffers (gldrawable);
}
gboolean glwidget_make_current (GtkWidget *widget)
{
GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
return gdk_gl_drawable_gl_begin (gldrawable, glcontext);
}

View File

@ -0,0 +1,19 @@
#if !defined(INCLUDED_GTKUTIL_GLWIDGET_H)
#define INCLUDED_GTKUTIL_GLWIDGET_H
typedef struct _GtkWidget GtkWidget;
typedef int gint;
typedef gint gboolean;
GtkWidget* glwidget_new(gboolean zbuffer);
void glwidget_swap_buffers(GtkWidget* widget);
gboolean glwidget_make_current(GtkWidget* widget);
void glwidget_destroy_context(GtkWidget* widget);
void glwidget_create_context(GtkWidget* widget);
extern void (*GLWidget_sharedContextCreated)();
extern void (*GLWidget_sharedContextDestroyed)();
#endif

View File

@ -0,0 +1,255 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="gtkutil"
ProjectGUID="{68E2C6B6-96CA-4BBD-A485-FEE6F2E65407}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="4"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../include;../;&quot;../../../STLPort-4.6/stlport&quot;;&quot;../../../gtk2-2.4/lib/glib-2.0/include&quot;;&quot;../../../gtk2-2.4/include/glib-2.0&quot;;&quot;../../../gtk2-2.4/lib/gtk-2.0/include&quot;;&quot;../../../gtk2-2.4/include/gtk-2.0&quot;;&quot;../../../gtk2-2.4/include/gtk-2.0/gdk&quot;;&quot;../../../gtk2-2.4/include/pango-1.0&quot;;&quot;../../../gtk2-2.4/include/atk-1.0&quot;;&quot;../../../gtk2-2.4/lib/gtkglext-1.0/include&quot;;&quot;../../../gtk2-2.4/include/gtkglext-1.0&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
StringPooling="TRUE"
MinimalRebuild="TRUE"
ExceptionHandling="FALSE"
BasicRuntimeChecks="0"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
BrowseInformation="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"
DisableSpecificWarnings="4610;4510;4512;4505;4100;4127"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/gtkutil.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"
IntermediateDirectory="Release"
ConfigurationType="4"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
OptimizeForWindowsApplication="TRUE"
AdditionalIncludeDirectories="../../include;../;&quot;../../../STLPort-4.6/stlport&quot;;&quot;../../../gtk2-2.4/lib/glib-2.0/include&quot;;&quot;../../../gtk2-2.4/include/glib-2.0&quot;;&quot;../../../gtk2-2.4/lib/gtk-2.0/include&quot;;&quot;../../../gtk2-2.4/include/gtk-2.0&quot;;&quot;../../../gtk2-2.4/include/gtk-2.0/gdk&quot;;&quot;../../../gtk2-2.4/include/pango-1.0&quot;;&quot;../../../gtk2-2.4/include/atk-1.0&quot;;&quot;../../../gtk2-2.4/lib/gtkglext-1.0/include&quot;;&quot;../../../gtk2-2.4/include/gtkglext-1.0&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
StringPooling="TRUE"
ExceptionHandling="FALSE"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"
DisableSpecificWarnings="4610;4510;4512;4505;4100;4127"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/gtkutil.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>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="src"
Filter="">
<File
RelativePath=".\accelerator.cpp">
</File>
<File
RelativePath=".\accelerator.h">
</File>
<File
RelativePath=".\button.cpp">
</File>
<File
RelativePath=".\button.h">
</File>
<File
RelativePath=".\clipboard.cpp">
</File>
<File
RelativePath=".\clipboard.h">
</File>
<File
RelativePath=".\closure.cpp">
</File>
<File
RelativePath=".\closure.h">
</File>
<File
RelativePath=".\container.cpp">
</File>
<File
RelativePath=".\container.h">
</File>
<File
RelativePath=".\cursor.cpp">
</File>
<File
RelativePath=".\cursor.h">
</File>
<File
RelativePath=".\dialog.cpp">
</File>
<File
RelativePath=".\dialog.h">
</File>
<File
RelativePath=".\entry.cpp">
</File>
<File
RelativePath=".\entry.h">
</File>
<File
RelativePath=".\filechooser.cpp">
</File>
<File
RelativePath=".\filechooser.h">
</File>
<File
RelativePath=".\frame.cpp">
</File>
<File
RelativePath=".\frame.h">
</File>
<File
RelativePath=".\glfont.cpp">
</File>
<File
RelativePath=".\glfont.h">
</File>
<File
RelativePath=".\glwidget.cpp">
</File>
<File
RelativePath=".\glwidget.h">
</File>
<File
RelativePath=".\idledraw.cpp">
</File>
<File
RelativePath=".\idledraw.h">
</File>
<File
RelativePath=".\image.cpp">
</File>
<File
RelativePath=".\image.h">
</File>
<File
RelativePath=".\menu.cpp">
</File>
<File
RelativePath=".\menu.h">
</File>
<File
RelativePath=".\messagebox.cpp">
</File>
<File
RelativePath=".\messagebox.h">
</File>
<File
RelativePath=".\nonmodal.cpp">
</File>
<File
RelativePath=".\nonmodal.h">
</File>
<File
RelativePath=".\paned.cpp">
</File>
<File
RelativePath=".\paned.h">
</File>
<File
RelativePath=".\pointer.cpp">
</File>
<File
RelativePath=".\pointer.h">
</File>
<File
RelativePath=".\toolbar.cpp">
</File>
<File
RelativePath=".\toolbar.h">
</File>
<File
RelativePath=".\widget.cpp">
</File>
<File
RelativePath=".\widget.h">
</File>
<File
RelativePath=".\window.cpp">
</File>
<File
RelativePath=".\window.h">
</File>
<File
RelativePath=".\xorrectangle.cpp">
</File>
<File
RelativePath=".\xorrectangle.h">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,3 @@
#include "idledraw.h"

View File

@ -0,0 +1,49 @@
#if !defined(INCLUDED_GTKUTIL_IDLEDRAW_H)
#define INCLUDED_GTKUTIL_IDLEDRAW_H
#include <glib/gmain.h>
#include "generic/callback.h"
class IdleDraw
{
Callback m_draw;
unsigned int m_handler;
static gboolean draw(gpointer data)
{
reinterpret_cast<IdleDraw*>(data)->m_draw();
reinterpret_cast<IdleDraw*>(data)->m_handler = 0;
return FALSE;
}
public:
IdleDraw(const Callback& draw) : m_draw(draw), m_handler(0)
{
}
~IdleDraw()
{
if(m_handler != 0)
{
g_source_remove(m_handler);
}
}
void queueDraw()
{
if(m_handler == 0)
{
m_handler = g_idle_add(&draw, this);
}
}
typedef MemberCaller<IdleDraw, &IdleDraw::queueDraw> QueueDrawCaller;
void flush()
{
if(m_handler != 0)
{
draw(this);
}
}
};
#endif

View File

@ -0,0 +1,76 @@
#include "image.h"
#include <gtk/gtkimage.h>
#include <gtk/gtkstock.h>
#include "string/string.h"
#include "stream/stringstream.h"
#include "stream/textstream.h"
namespace
{
CopiedString g_bitmapsPath;
}
void BitmapsPath_set(const char* path)
{
g_bitmapsPath = path;
}
GdkPixbuf* pixbuf_new_from_file_with_mask(const char* filename)
{
GdkPixbuf* rgb = gdk_pixbuf_new_from_file(filename, 0);
if(rgb == 0)
{
return 0;
}
else
{
GdkPixbuf* rgba = gdk_pixbuf_add_alpha(rgb, TRUE, 255, 0, 255);
gdk_pixbuf_unref(rgb);
return rgba;
}
}
GtkImage* image_new_from_file_with_mask(const char* filename)
{
GdkPixbuf* rgba = pixbuf_new_from_file_with_mask(filename);
if(rgba == 0)
{
return 0;
}
else
{
GtkImage* image = GTK_IMAGE(gtk_image_new_from_pixbuf(rgba));
gdk_pixbuf_unref(rgba);
return image;
}
}
GtkImage* image_new_missing()
{
return GTK_IMAGE(gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_SMALL_TOOLBAR));
}
GtkImage* new_image(const char* filename)
{
{
GtkImage* image = image_new_from_file_with_mask(filename);
if(image != 0)
{
return image;
}
}
return image_new_missing();
}
GtkImage* new_local_image(const char* filename)
{
StringOutputStream fullPath(256);
fullPath << g_bitmapsPath.c_str() << filename;
return new_image(fullPath.c_str());
}

View File

@ -0,0 +1,16 @@
#if !defined(INCLUDED_GTKUTIL_IMAGE_H)
#define INCLUDED_GTKUTIL_IMAGE_H
void BitmapsPath_set(const char* path);
typedef struct _GtkImage GtkImage;
typedef struct _GdkPixbuf GdkPixbuf;
GdkPixbuf* pixbuf_new_from_file_with_mask(const char* filename);
GtkImage* image_new_from_file_with_mask(const char* filename);
GtkImage* image_new_missing();
GtkImage* new_image(const char* filename); // filename is full path to image file
GtkImage* new_local_image(const char* filename); // filename is relative to local bitmaps path
#endif

View File

@ -0,0 +1,293 @@
#include "menu.h"
#include <ctype.h>
#include <gtk/gtkmenu.h>
#include <gtk/gtkmenubar.h>
#include <gtk/gtkradiomenuitem.h>
#include <gtk/gtktearoffmenuitem.h>
#include <gtk/gtkaccellabel.h>
#include "generic/callback.h"
#include "accelerator.h"
#include "closure.h"
#include "container.h"
#include "pointer.h"
void menu_add_item(GtkMenu* menu, GtkMenuItem* item)
{
gtk_container_add(GTK_CONTAINER(menu), GTK_WIDGET(item));
}
GtkMenuItem* menu_separator(GtkMenu* menu)
{
GtkMenuItem* menu_item = GTK_MENU_ITEM(gtk_menu_item_new());
container_add_widget(GTK_CONTAINER(menu), GTK_WIDGET(menu_item));
gtk_widget_set_sensitive(GTK_WIDGET(menu_item), FALSE);
gtk_widget_show(GTK_WIDGET(menu_item));
return menu_item;
}
GtkTearoffMenuItem* menu_tearoff(GtkMenu* menu)
{
GtkTearoffMenuItem* menu_item = GTK_TEAROFF_MENU_ITEM(gtk_tearoff_menu_item_new());
container_add_widget(GTK_CONTAINER(menu), GTK_WIDGET(menu_item));
// gtk_widget_set_sensitive(GTK_WIDGET(menu_item), FALSE); -- controls whether menu is detachable
gtk_widget_show(GTK_WIDGET(menu_item));
return menu_item;
}
GtkMenuItem* new_sub_menu_item_with_mnemonic(const char* mnemonic)
{
GtkMenuItem* item = GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(mnemonic));
gtk_widget_show(GTK_WIDGET(item));
GtkWidget* sub_menu = gtk_menu_new();
gtk_menu_item_set_submenu(item, sub_menu);
return item;
}
GtkMenu* create_sub_menu_with_mnemonic(GtkMenuShell* parent, const char* mnemonic)
{
GtkMenuItem* item = new_sub_menu_item_with_mnemonic(mnemonic);
container_add_widget(GTK_CONTAINER(parent), GTK_WIDGET(item));
return GTK_MENU(gtk_menu_item_get_submenu(item));
}
GtkMenu* create_sub_menu_with_mnemonic(GtkMenuBar* bar, const char* mnemonic)
{
return create_sub_menu_with_mnemonic(GTK_MENU_SHELL(bar), mnemonic);
}
GtkMenu* create_sub_menu_with_mnemonic(GtkMenu* parent, const char* mnemonic)
{
return create_sub_menu_with_mnemonic(GTK_MENU_SHELL(parent), mnemonic);
}
void activate_closure_callback(GtkWidget* widget, gpointer data)
{
(*reinterpret_cast<Callback*>(data))();
}
guint menu_item_connect_callback(GtkMenuItem* item, const Callback& callback)
{
#if 1
return g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(callback.getThunk()), callback.getEnvironment());
#else
return g_signal_connect_closure(G_OBJECT(item), "activate", create_cclosure(G_CALLBACK(activate_closure_callback), callback), FALSE);
#endif
}
guint check_menu_item_connect_callback(GtkCheckMenuItem* item, const Callback& callback)
{
#if 1
guint handler = g_signal_connect_swapped(G_OBJECT(item), "toggled", G_CALLBACK(callback.getThunk()), callback.getEnvironment());
#else
guint handler = g_signal_connect_closure(G_OBJECT(item), "toggled", create_cclosure(G_CALLBACK(activate_closure_callback), callback), TRUE);
#endif
g_object_set_data(G_OBJECT(item), "handler", gint_to_pointer(handler));
return handler;
}
GtkMenuItem* new_menu_item_with_mnemonic(const char *mnemonic, const Callback& callback)
{
GtkMenuItem* item = GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(mnemonic));
gtk_widget_show(GTK_WIDGET(item));
menu_item_connect_callback(item, callback);
return item;
}
GtkMenuItem* create_menu_item_with_mnemonic(GtkMenu* menu, const char *mnemonic, const Callback& callback)
{
GtkMenuItem* item = new_menu_item_with_mnemonic(mnemonic, callback);
container_add_widget(GTK_CONTAINER(menu), GTK_WIDGET(item));
return item;
}
GtkCheckMenuItem* new_check_menu_item_with_mnemonic(const char* mnemonic, const Callback& callback)
{
GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(gtk_check_menu_item_new_with_mnemonic(mnemonic));
gtk_widget_show(GTK_WIDGET(item));
check_menu_item_connect_callback(item, callback);
return item;
}
GtkCheckMenuItem* create_check_menu_item_with_mnemonic(GtkMenu* menu, const char* mnemonic, const Callback& callback)
{
GtkCheckMenuItem* item = new_check_menu_item_with_mnemonic(mnemonic, callback);
container_add_widget(GTK_CONTAINER(menu), GTK_WIDGET(item));
return item;
}
GtkRadioMenuItem* new_radio_menu_item_with_mnemonic(GSList** group, const char* mnemonic, const Callback& callback)
{
GtkRadioMenuItem* item = GTK_RADIO_MENU_ITEM(gtk_radio_menu_item_new_with_mnemonic(*group, mnemonic));
if(*group == 0)
{
gtk_check_menu_item_set_state(GTK_CHECK_MENU_ITEM(item), TRUE);
}
*group = gtk_radio_menu_item_group(item);
gtk_widget_show(GTK_WIDGET(item));
check_menu_item_connect_callback(GTK_CHECK_MENU_ITEM(item), callback);
return item;
}
GtkRadioMenuItem* create_radio_menu_item_with_mnemonic(GtkMenu* menu, GSList** group, const char* mnemonic, const Callback& callback)
{
GtkRadioMenuItem* item = new_radio_menu_item_with_mnemonic(group, mnemonic, callback);
container_add_widget(GTK_CONTAINER(menu), GTK_WIDGET(item));
return item;
}
void check_menu_item_set_active_no_signal(GtkCheckMenuItem* item, gboolean active)
{
guint handler_id = gpointer_to_int(g_object_get_data(G_OBJECT(item), "handler"));
g_signal_handler_block(G_OBJECT(item), handler_id);
gtk_check_menu_item_set_active(item, active);
g_signal_handler_unblock(G_OBJECT(item), handler_id);
}
void radio_menu_item_set_active_no_signal(GtkRadioMenuItem* item, gboolean active)
{
{
for(GSList* l = gtk_radio_menu_item_get_group(item); l != 0; l = g_slist_next(l))
{
g_signal_handler_block(G_OBJECT(l->data), gpointer_to_int(g_object_get_data(G_OBJECT(l->data), "handler")));
}
}
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), active);
{
for(GSList* l = gtk_radio_menu_item_get_group(item); l != 0; l = g_slist_next(l))
{
g_signal_handler_unblock(G_OBJECT(l->data), gpointer_to_int(g_object_get_data(G_OBJECT(l->data), "handler")));
}
}
}
void menu_item_set_accelerator(GtkMenuItem* item, GClosure* closure)
{
GtkAccelLabel* accel_label = GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(item)));
gtk_accel_label_set_accel_closure(accel_label, closure);
}
void accelerator_name(const Accelerator& accelerator, GString* gstring)
{
gboolean had_mod = FALSE;
if (accelerator.modifiers & GDK_SHIFT_MASK)
{
g_string_append (gstring, "Shift");
had_mod = TRUE;
}
if (accelerator.modifiers & GDK_CONTROL_MASK)
{
if (had_mod)
g_string_append (gstring, "+");
g_string_append (gstring, "Ctrl");
had_mod = TRUE;
}
if (accelerator.modifiers & GDK_MOD1_MASK)
{
if (had_mod)
g_string_append (gstring, "+");
g_string_append (gstring, "Alt");
had_mod = TRUE;
}
if (had_mod)
g_string_append (gstring, "+");
if (accelerator.key < 0x80 || (accelerator.key > 0x80 && accelerator.key <= 0xff))
{
switch (accelerator.key)
{
case ' ':
g_string_append (gstring, "Space");
break;
case '\\':
g_string_append (gstring, "Backslash");
break;
default:
g_string_append_c (gstring, gchar(toupper(accelerator.key)));
break;
}
}
else
{
gchar *tmp;
tmp = gtk_accelerator_name (accelerator.key, (GdkModifierType)0);
if (tmp[0] != 0 && tmp[1] == 0)
tmp[0] = gchar(toupper(tmp[0]));
g_string_append (gstring, tmp);
g_free (tmp);
}
}
void menu_item_set_accelerator(GtkMenuItem* item, Accelerator accelerator)
{
GtkAccelLabel* accel_label = GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(item)));
g_free (accel_label->accel_string);
accel_label->accel_string = 0;
GString* gstring = g_string_new (accel_label->accel_string);
g_string_append (gstring, " ");
accelerator_name(accelerator, gstring);
g_free (accel_label->accel_string);
accel_label->accel_string = gstring->str;
g_string_free (gstring, FALSE);
if (!accel_label->accel_string)
accel_label->accel_string = g_strdup ("");
gtk_widget_queue_resize (GTK_WIDGET (accel_label));
}
void menu_item_add_accelerator(GtkMenuItem* item, Accelerator accelerator)
{
if(accelerator.key != 0)
{
GClosure* closure = global_accel_group_find(accelerator);
if(closure != 0)
{
menu_item_set_accelerator(item, closure);
}
else
{
menu_item_set_accelerator(item, accelerator);
}
}
}
GtkMenuItem* create_menu_item_with_mnemonic(GtkMenu* menu, const char* mnemonic, const Command& command)
{
command_connect_accelerator(command.m_accelerator, command.m_callback);
GtkMenuItem* item = create_menu_item_with_mnemonic(menu, mnemonic, command.m_callback);
menu_item_add_accelerator(item, command.m_accelerator);
return item;
}
void check_menu_item_set_active_callback(GtkCheckMenuItem& item, bool enabled)
{
check_menu_item_set_active_no_signal(&item, enabled);
}
typedef ReferenceCaller1<GtkCheckMenuItem, bool, check_menu_item_set_active_callback> CheckMenuItemSetActiveCaller;
GtkCheckMenuItem* create_check_menu_item_with_mnemonic(GtkMenu* menu, const char* mnemonic, const Toggle& toggle)
{
command_connect_accelerator(toggle.m_command.m_accelerator, toggle.m_command.m_callback);
GtkCheckMenuItem* item = create_check_menu_item_with_mnemonic(menu, mnemonic, toggle.m_command.m_callback);
menu_item_add_accelerator(GTK_MENU_ITEM(item), toggle.m_command.m_accelerator);
toggle.m_exportCallback(CheckMenuItemSetActiveCaller(*item));
return item;
}

View File

@ -0,0 +1,37 @@
#if !defined(INCLUDED_GTKUTIL_MENU_H)
#define INCLUDED_GTKUTIL_MENU_H
class Callback;
typedef int gint;
typedef gint gboolean;
typedef struct _GSList GSList;
typedef struct _GtkMenu GtkMenu;
typedef struct _GtkMenuBar GtkMenuBar;
typedef struct _GtkMenuItem GtkMenuItem;
typedef struct _GtkCheckMenuItem GtkCheckMenuItem;
typedef struct _GtkRadioMenuItem GtkRadioMenuItem;
typedef struct _GtkTearoffMenuItem GtkTearoffMenuItem;
void menu_add_item(GtkMenu* menu, GtkMenuItem* item);
GtkMenuItem* menu_separator(GtkMenu* menu);
GtkTearoffMenuItem* menu_tearoff(GtkMenu* menu);
GtkMenuItem* new_sub_menu_item_with_mnemonic(const char* mnemonic);
GtkMenu* create_sub_menu_with_mnemonic(GtkMenuBar* bar, const char* mnemonic);
GtkMenu* create_sub_menu_with_mnemonic(GtkMenu* parent, const char* mnemonic);
GtkMenuItem* create_menu_item_with_mnemonic(GtkMenu* menu, const char* mnemonic, const Callback& callback);
GtkCheckMenuItem* create_check_menu_item_with_mnemonic(GtkMenu* menu, const char* mnemonic, const Callback& callback);
GtkRadioMenuItem* create_radio_menu_item_with_mnemonic(GtkMenu* menu, GSList** group, const char* mnemonic, const Callback& callback);
class Command;
GtkMenuItem* create_menu_item_with_mnemonic(GtkMenu* menu, const char* mnemonic, const Command& command);
class Toggle;
GtkCheckMenuItem* create_check_menu_item_with_mnemonic(GtkMenu* menu, const char* mnemonic, const Toggle& toggle);
typedef struct _GtkCheckMenuItem GtkCheckMenuItem;
void check_menu_item_set_active_no_signal(GtkCheckMenuItem* item, gboolean active);
typedef struct _GtkRadioMenuItem GtkRadioMenuItem;
void radio_menu_item_set_active_no_signal(GtkRadioMenuItem* item, gboolean active);
#endif

View File

@ -0,0 +1,193 @@
#include "messagebox.h"
#include <gdk/gdkkeysyms.h>
#include <gtk/gtkmain.h>
#include <gtk/gtkwindow.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkalignment.h>
#include <gtk/gtkbutton.h>
#include <gtk/gtkimage.h>
#include <gtk/gtkstock.h>
#include "dialog.h"
#include "widget.h"
GtkWidget* create_padding(int width, int height)
{
GtkWidget* widget = gtk_alignment_new(0.0, 0.0, 0.0, 0.0);
gtk_widget_show(widget);
gtk_widget_set_size_request(widget, width, height);
return widget;
}
const char* messagebox_stock_icon(EMessageBoxIcon type)
{
switch(type)
{
default:
case eMB_ICONDEFAULT:
return GTK_STOCK_DIALOG_INFO;
case eMB_ICONERROR:
return GTK_STOCK_DIALOG_ERROR;
case eMB_ICONWARNING:
return GTK_STOCK_DIALOG_WARNING;
case eMB_ICONQUESTION:
return GTK_STOCK_DIALOG_QUESTION;
case eMB_ICONASTERISK:
return GTK_STOCK_DIALOG_INFO;
}
}
EMessageBoxReturn gtk_MessageBox (GtkWidget *parent, const char* text, const char* title, EMessageBoxType type, EMessageBoxIcon icon)
{
ModalDialog dialog;
ModalDialogButton ok_button(dialog, eIDOK);
ModalDialogButton cancel_button(dialog, eIDCANCEL);
ModalDialogButton yes_button(dialog, eIDYES);
ModalDialogButton no_button(dialog, eIDNO);
GtkWindow* parentWindow = parent != 0 ? GTK_WINDOW(parent) : 0;
GtkWindow* window = create_fixedsize_modal_dialog_window(parentWindow, title, dialog, 400, 100);
if(parentWindow != 0)
{
//g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(floating_window_delete_present), parent);
gtk_window_deiconify(parentWindow);
}
GtkAccelGroup* accel = gtk_accel_group_new();
gtk_window_add_accel_group(window, accel);
GtkVBox* vbox = create_dialog_vbox(8, 8);
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
GtkHBox* hboxDummy = create_dialog_hbox(0, 0);
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hboxDummy), FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hboxDummy), create_padding(0, 50), FALSE, FALSE, 0); // HACK to force minimum height
GtkHBox* iconBox = create_dialog_hbox(16, 0);
gtk_box_pack_start(GTK_BOX(hboxDummy), GTK_WIDGET(iconBox), FALSE, FALSE, 0);
GtkImage* image = GTK_IMAGE(gtk_image_new_from_stock(messagebox_stock_icon(icon), GTK_ICON_SIZE_DIALOG));
gtk_widget_show(GTK_WIDGET(image));
gtk_box_pack_start(GTK_BOX(iconBox), GTK_WIDGET(image), FALSE, FALSE, 0);
GtkLabel* label = GTK_LABEL(gtk_label_new(text));
gtk_widget_show(GTK_WIDGET(label));
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
gtk_label_set_justify(label, GTK_JUSTIFY_LEFT);
gtk_label_set_line_wrap(label, TRUE);
gtk_box_pack_start(GTK_BOX(iconBox), GTK_WIDGET(label), TRUE, TRUE, 0);
GtkVBox* vboxDummy = create_dialog_vbox(0, 0);
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(vboxDummy), FALSE, FALSE, 0);
GtkAlignment* alignment = GTK_ALIGNMENT(gtk_alignment_new(0.5, 0.0, 0.0, 0.0));
gtk_widget_show(GTK_WIDGET(alignment));
gtk_box_pack_start(GTK_BOX(vboxDummy), GTK_WIDGET(alignment), FALSE, FALSE, 0);
GtkHBox* hbox = create_dialog_hbox(8, 0);
gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(hbox));
gtk_box_pack_start(GTK_BOX(vboxDummy), create_padding(400, 0), FALSE, FALSE, 0); // HACK to force minimum width
if (type == eMB_OK)
{
GtkButton* button = create_modal_dialog_button("OK", ok_button);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), TRUE, FALSE, 0);
gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
widget_make_default(GTK_WIDGET(button));
gtk_widget_show(GTK_WIDGET(button));
dialog.ret = eIDOK;
}
else if (type == eMB_OKCANCEL)
{
{
GtkButton* button = create_modal_dialog_button("OK", ok_button);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), TRUE, FALSE, 0);
gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
widget_make_default(GTK_WIDGET(button));
gtk_widget_show(GTK_WIDGET(button));
}
{
GtkButton* button = create_modal_dialog_button("OK", cancel_button);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), TRUE, FALSE, 0);
gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
gtk_widget_show(GTK_WIDGET(button));
}
dialog.ret = eIDCANCEL;
}
else if (type == eMB_YESNOCANCEL)
{
{
GtkButton* button = create_modal_dialog_button("Yes", yes_button);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), TRUE, FALSE, 0);
widget_make_default(GTK_WIDGET(button));
gtk_widget_show(GTK_WIDGET(button));
}
{
GtkButton* button = create_modal_dialog_button("No", no_button);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), TRUE, FALSE, 0);
gtk_widget_show(GTK_WIDGET(button));
}
{
GtkButton* button = create_modal_dialog_button("Cancel", cancel_button);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), TRUE, FALSE, 0);
gtk_widget_show(GTK_WIDGET(button));
}
dialog.ret = eIDCANCEL;
}
else if (type == eMB_NOYES)
{
{
GtkButton* button = create_modal_dialog_button("No", no_button);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), TRUE, FALSE, 0);
widget_make_default(GTK_WIDGET(button));
gtk_widget_show(GTK_WIDGET(button));
}
{
GtkButton* button = create_modal_dialog_button("Yes", yes_button);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), TRUE, FALSE, 0);
gtk_widget_show(GTK_WIDGET(button));
}
dialog.ret = eIDNO;
}
else /* if (type == eMB_YESNO) */
{
{
GtkButton* button = create_modal_dialog_button("Yes", yes_button);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), TRUE, FALSE, 0);
widget_make_default(GTK_WIDGET(button));
gtk_widget_show(GTK_WIDGET(button));
}
{
GtkButton* button = create_modal_dialog_button("No", no_button);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), TRUE, FALSE, 0);
gtk_widget_show(GTK_WIDGET(button));
}
dialog.ret = eIDNO;
}
modal_dialog_show(window, dialog);
gtk_widget_destroy(GTK_WIDGET(window));
return dialog.ret;
}

View File

@ -0,0 +1,11 @@
#if !defined(INCLUDED_GTKUTIL_MESSAGEBOX_H)
#define INCLUDED_GTKUTIL_MESSAGEBOX_H
#include "qerplugin.h"
typedef struct _GtkWidget GtkWidget;
/// \brief Shows a modal message-box.
EMessageBoxReturn gtk_MessageBox(GtkWidget *parent, const char* text, const char* title = "GtkRadiant", EMessageBoxType type = eMB_OK, EMessageBoxIcon icon = eMB_ICONDEFAULT);
#endif

View File

@ -0,0 +1,3 @@
#include "nonmodal.h"

View File

@ -0,0 +1,166 @@
#if !defined(INCLUDED_GTKUTIL_NONMODAL_H)
#define INCLUDED_GTKUTIL_NONMODAL_H
#include <gtk/gtkwindow.h>
#include <gtk/gtkspinbutton.h>
#include <gtk/gtkradiobutton.h>
#include <gdk/gdkkeysyms.h>
#include "generic/callback.h"
#include "pointer.h"
#include "button.h"
typedef struct _GtkEntry GtkEntry;
inline gboolean escape_clear_focus_widget(GtkWidget* widget, GdkEventKey* event, gpointer data)
{
if(event->keyval == GDK_Escape)
{
gtk_window_set_focus(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(widget))), NULL);
return TRUE;
}
return FALSE;
}
inline void widget_connect_escape_clear_focus_widget(GtkWidget* widget)
{
g_signal_connect(G_OBJECT(widget), "key_press_event", G_CALLBACK(escape_clear_focus_widget), 0);
}
class NonModalEntry
{
bool m_editing;
Callback m_apply;
Callback m_cancel;
static gboolean focus_in(GtkEntry* entry, GdkEventFocus *event, NonModalEntry* self)
{
self->m_editing = false;
return FALSE;
}
static gboolean focus_out(GtkEntry* entry, GdkEventFocus *event, NonModalEntry* self)
{
if(self->m_editing && GTK_WIDGET_VISIBLE(entry))
{
self->m_apply();
}
self->m_editing = false;
return FALSE;
}
static gboolean changed(GtkEntry* entry, NonModalEntry* self)
{
self->m_editing = true;
return FALSE;
}
static gboolean enter(GtkEntry* entry, GdkEventKey* event, NonModalEntry* self)
{
if(event->keyval == GDK_Return)
{
self->m_apply();
self->m_editing = false;
gtk_window_set_focus(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(entry))), NULL);
return TRUE;
}
return FALSE;
}
static gboolean escape(GtkEntry* entry, GdkEventKey* event, NonModalEntry* self)
{
if(event->keyval == GDK_Escape)
{
self->m_cancel();
self->m_editing = false;
gtk_window_set_focus(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(entry))), NULL);
return TRUE;
}
return FALSE;
}
public:
NonModalEntry(const Callback& apply, const Callback& cancel) : m_editing(false), m_apply(apply), m_cancel(cancel)
{
}
void connect(GtkEntry* entry)
{
g_signal_connect(G_OBJECT(entry), "focus_in_event", G_CALLBACK(focus_in), this);
g_signal_connect(G_OBJECT(entry), "focus_out_event", G_CALLBACK(focus_out), this);
g_signal_connect(G_OBJECT(entry), "key_press_event", G_CALLBACK(enter), this);
g_signal_connect(G_OBJECT(entry), "key_press_event", G_CALLBACK(escape), this);
g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(changed), this);
}
};
class NonModalSpinner
{
Callback m_apply;
Callback m_cancel;
static gboolean changed(GtkSpinButton* spin, NonModalSpinner* self)
{
self->m_apply();
return FALSE;
}
static gboolean enter(GtkSpinButton* spin, GdkEventKey* event, NonModalSpinner* self)
{
if(event->keyval == GDK_Return)
{
gtk_window_set_focus(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(spin))), NULL);
return TRUE;
}
return FALSE;
}
static gboolean escape(GtkSpinButton* spin, GdkEventKey* event, NonModalSpinner* self)
{
if(event->keyval == GDK_Escape)
{
self->m_cancel();
gtk_window_set_focus(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(spin))), NULL);
return TRUE;
}
return FALSE;
}
public:
NonModalSpinner(const Callback& apply, const Callback& cancel) : m_apply(apply), m_cancel(cancel)
{
}
void connect(GtkSpinButton* spin)
{
guint handler = g_signal_connect(G_OBJECT(gtk_spin_button_get_adjustment(spin)), "value_changed", G_CALLBACK(changed), this);
g_object_set_data(G_OBJECT(spin), "handler", gint_to_pointer(handler));
g_signal_connect(G_OBJECT(spin), "key_press_event", G_CALLBACK(enter), this);
g_signal_connect(G_OBJECT(spin), "key_press_event", G_CALLBACK(escape), this);
}
};
class NonModalRadio
{
Callback m_changed;
public:
NonModalRadio(const Callback& changed) : m_changed(changed)
{
}
void connect(GtkRadioButton* radio)
{
GSList* group = gtk_radio_button_group(radio);
for(; group != 0; group = g_slist_next(group))
{
toggle_button_connect_callback(GTK_TOGGLE_BUTTON(group->data), m_changed);
}
}
};
#endif

View File

@ -0,0 +1,80 @@
#include "paned.h"
#include <gtk/gtkhpaned.h>
#include <gtk/gtkvpaned.h>
#include "frame.h"
class PanedState
{
public:
float position;
int size;
};
gboolean hpaned_allocate(GtkWidget* widget, GtkAllocation* allocation, PanedState* paned)
{
if(paned->size != allocation->width)
{
paned->size = allocation->width;
gtk_paned_set_position (GTK_PANED (widget), static_cast<int>(paned->size * paned->position));
}
return FALSE;
}
gboolean vpaned_allocate(GtkWidget* widget, GtkAllocation* allocation, PanedState* paned)
{
if(paned->size != allocation->height)
{
paned->size = allocation->height;
gtk_paned_set_position (GTK_PANED (widget), static_cast<int>(paned->size * paned->position));
}
return FALSE;
}
gboolean paned_position(GtkWidget* widget, gpointer dummy, PanedState* paned)
{
if(paned->size != -1)
paned->position = gtk_paned_get_position (GTK_PANED (widget)) / static_cast<float>(paned->size);
return FALSE;
}
PanedState g_hpaned = { 0.5f, -1, };
PanedState g_vpaned1 = { 0.5f, -1, };
PanedState g_vpaned2 = { 0.5f, -1, };
GtkHPaned* create_split_views(GtkWidget* topleft, GtkWidget* topright, GtkWidget* botleft, GtkWidget* botright)
{
GtkHPaned* hsplit = GTK_HPANED(gtk_hpaned_new());
gtk_widget_show(GTK_WIDGET(hsplit));
g_signal_connect(G_OBJECT(hsplit), "size_allocate", G_CALLBACK(hpaned_allocate), &g_hpaned);
g_signal_connect(G_OBJECT(hsplit), "notify::position", G_CALLBACK(paned_position), &g_hpaned);
{
GtkVPaned* vsplit = GTK_VPANED(gtk_vpaned_new());
gtk_paned_add1(GTK_PANED(hsplit), GTK_WIDGET(vsplit));
gtk_widget_show(GTK_WIDGET(vsplit));
g_signal_connect(G_OBJECT(vsplit), "size_allocate", G_CALLBACK(vpaned_allocate), &g_vpaned1);
g_signal_connect(G_OBJECT(vsplit), "notify::position", G_CALLBACK(paned_position), &g_vpaned1);
gtk_paned_add1(GTK_PANED(vsplit), GTK_WIDGET(create_framed_widget(topleft)));
gtk_paned_add2(GTK_PANED(vsplit), GTK_WIDGET(create_framed_widget(topright)));
}
{
GtkVPaned* vsplit = GTK_VPANED(gtk_vpaned_new());
gtk_paned_add2(GTK_PANED(hsplit), GTK_WIDGET(vsplit));
gtk_widget_show(GTK_WIDGET(vsplit));
g_signal_connect(G_OBJECT(vsplit), "size_allocate", G_CALLBACK(vpaned_allocate), &g_vpaned2);
g_signal_connect(G_OBJECT(vsplit), "notify::position", G_CALLBACK(paned_position), &g_vpaned2);
gtk_paned_add1(GTK_PANED(vsplit), GTK_WIDGET(create_framed_widget(botleft)));
gtk_paned_add2(GTK_PANED(vsplit), GTK_WIDGET(create_framed_widget(botright)));
}
return hsplit;
}

Some files were not shown because too many files have changed in this diff Show More