Separate from WorldSpawn

This commit is contained in:
Marco Cawthorne 2023-10-08 20:21:07 -07:00
parent 3026ccf374
commit 2ae68a5c85
Signed by: eukara
GPG key ID: CE2032F0A2882A22
694 changed files with 167 additions and 162291 deletions

View file

@ -1,13 +1,7 @@
all:
mkdir -p ./build
cd libs && $(MAKE)
cd src && $(MAKE)
cd plugins && $(MAKE)
cd tools && $(MAKE)
cd resources && $(MAKE)
clean:
cd libs && $(MAKE) clean
cd src && $(MAKE) clean
cd plugins && $(MAKE) clean
cd tools && $(MAKE) clean

View file

@ -1,83 +1,64 @@
# ![WorldSpawn Logo](icon.png) WorldSpawn
The worlds most opinionated fork of Radiant.
# vmap
The editor we use at Vera Visions to create BSP levels.
It was forked from NetRadiant in June of 2018 and was a result of necessity.
A fork of q3map2, now available as a stand-alone compiler targetting [FTEQW](https://www.fteqw.org/)
We wanted to move away from a proprietary toolchain that had technical issues the developer would not ever get back to us about, so we ended up here.
Use it if you actually want to use the features listed below - note that they require a modified engine as our BSP format is different from standard idTech 3 BSP.
You will not be able to make levels compatible with other games and engines.
There's plenty of other editors for the first-party id Tech games.
**Please use those instead if you want to use a level editor with actual support, submission for feature requests, etc. - we are only sharing this because that's the best way of preserving software.**
**Please respect this notice, thank you.**
![Screenshot](docs/screen.jpg)
## Editor Changes
- Valve 220 format is used **top to bottom**, **imported & exported**, with texture coords handled internally the same way, including the compiler
- Integration with our **own material format** (no more giant .shader files)
- Support for vertex-color/alpha editing of patches using our new **fixed patch format**, allowing technologies such as **4-way texture blending** and whatever your designers can imagine
- Gracefully deals with duplicate entity attribute key/value pairs, to support features like Source Engine style **Input/Output system** for triggers
- Support for **VVM** (based on IQM) model format in the BSP compiler as well as the editor
- Support for **internal** and external **High-Dynamic-Range lightmaps** in the BSP compiler
- Support for **cubemap aware surfaces** in the BSP compiler
- Support for our patchDef2WS and patchDef3WS curved surfaces in the BSP compiler
- *More bug-fixes than you could possibly imagine*
## Why
Back then there was no fork of Radiant supporting the 220 format like said program had exported.
We had to make that happen on our own, since then we've expanded and kept changing more to meet our own needs.
On top of that, there's other benefits from working in our own Radiant fork.
Rapid experimentation and tech development doesn't fit into an editor like GtkRadiant,
which aims to be stable, reliable and support a specific set of games really, really well.
We can afford to break compat here in order to achieve our goals. It will break, be unstable
and all that jazz at the cost of supporting the greatest and latest of we're working on.
Some code in here (like the IQM support in the compiler) has made it into other Radiant forks
when we deem it to be mature. However not everything in here is going to be of interest
to other Radiant forks.
A lot of the changes are specific to our BSP format & engine too.
So tech like per-surface picked and generated environment maps will never make it into other games.
Sorry!
## Compiler Changes
- Improved High-Dynamic-Range lightmaps
- Support for our patchDef2WS and patchDef3WS curved surfaces in the BSP compiler, allowing for 4-way texture blended patches.
- Reads individual material scripts (.mat) instead of large .shader files
- Surfaces are aware which env_cubemap ents they belong to
- light_surface entity support, so you don't have to write map specific materials to override texture light properties
- Handles Half-Life styled point lights, including zhlt_lightflags
- Handles Half-Life styled light_environment entities
- New material keys: vmap_lightLinear, vmap_lightLinearFade
- Support for target-less spotlights
- Explicit support for func_detail, func_detail_illusionary
- Support for misc_prefab (including other .map files)
- vmap_remapMaterial/q3map_remapShader can carry over surface flags now
- Support for entity key: _entsurfaceflags, so surfaces can override their surfaceflags
- Support for entity key: _entcontentflags, so brushes can override their contentflags
## Compiling
To compile on a standard GNU/Linux system:
`LDFLAGS=-ldl make -j $(nproc)`
`make`
On BSD you should probably use GNU make right now. The Makefiles are simple enough however.
Clang should also be supported, pass `CC=clang and CXX=clang++` if you want to use it.
On BSD you should probably use GNU make right now.
Clang should also be supported, pass `CC=clang` if you want to use it.
On NT you'll have to jump through a lot more hoops, here's the gist:
1. MSYS2: https://www.msys2.org/
2. in the msys2 shell, enter `pacman -S --needed base-devel git unzip mingw-w64-$(uname -m)-{toolchain,make,gtk2,gtkglext,minizip-git}`
2. in the msys2 shell, enter `pacman -S --needed base-devel git unzip mingw-w64-$(uname -m)-{toolchain,make,minizip-git}`
3. boot into the Mingw64 shell, don't use the stock MSYS2 shell
4. run make and it should build everything, in theory
**Please don't contact us about helping you build it on Windows. This is a development tool. This is provided AS-IS.**
It'll compile everything into a subdirectory 'build'. At the end it'll copy files from ./resources into it too.
In the Nuclide SDK, build_editor.sh will call make with the appropriate flags for Linux/BSD automatically and
move it into Nuclide's ./bin directory.
## Dependencies
* GNU make
* gcc-core
* gcc-c++
* gtk2-devel
* gtkglext-devel
* glib2-devel
* libxml2-devel
* libjpeg8-devel
* libpng-devel
* minizip-devel
## Support
**As mentioned before, if you need help with this: you're on your own.**
Please use [GtkRadiant](https://github.com/TTimo/GtkRadiant) if you want to make levels for existing games.
## Special Thanks
The original q3map/2 developers:
- id Software
- Splash Damage
- ydnar
- GtkRadiant team and contributors
- NetRadiant team and contributors
vmap developers:
- Vera Visions, L.L.C.
- Spike
- Joshua Ashton
- Slartibarty

BIN
icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

View file

@ -1,52 +1,16 @@
all:
cd cmdlib && $(MAKE)
cd container && $(MAKE)
cd ddslib && $(MAKE)
cd debugging && $(MAKE)
cd etclib && $(MAKE)
cd filematch && $(MAKE)
cd generic && $(MAKE)
cd gtkutil && $(MAKE)
cd l_net && $(MAKE)
cd math && $(MAKE)
cd mathlib && $(MAKE)
#cd md5lib && $(MAKE)
cd memory && $(MAKE)
cd modulesystem && $(MAKE)
cd os && $(MAKE)
cd picomodel && $(MAKE)
cd profile && $(MAKE)
cd script && $(MAKE)
cd signal && $(MAKE)
cd splines && $(MAKE)
cd stream && $(MAKE)
cd string && $(MAKE)
cd uilib && $(MAKE)
cd xml && $(MAKE)
clean:
cd cmdlib && $(MAKE) clean
cd container && $(MAKE) clean
cd ddslib && $(MAKE) clean
cd debugging && $(MAKE) clean
cd etclib && $(MAKE) clean
cd filematch && $(MAKE) clean
cd generic && $(MAKE) clean
cd gtkutil && $(MAKE) clean
cd l_net && $(MAKE) clean
cd math && $(MAKE) clean
cd mathlib && $(MAKE) clean
#cd md5lib && $(MAKE) clean
cd memory && $(MAKE) clean
cd modulesystem && $(MAKE) clean
cd os && $(MAKE) clean
cd picomodel && $(MAKE) clean
cd profile && $(MAKE) clean
cd script && $(MAKE) clean
cd signal && $(MAKE) clean
cd splines && $(MAKE) clean
cd stream && $(MAKE) clean
cd string && $(MAKE) clean
cd uilib && $(MAKE) clean
cd xml && $(MAKE) clean

View file

@ -1 +0,0 @@

View file

@ -1,224 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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;
InputStreamType& m_inputStream;
byte_type m_buffer[SIZE];
byte_type* m_cur;
byte_type* m_end;
public:
SingleByteInputStream( InputStreamType& inputStream ) : m_inputStream( inputStream ), m_cur( m_buffer + SIZE ), m_end( m_cur ){
}
bool readByte( byte_type& b ){
if ( m_cur == m_end ) {
if ( m_end != m_buffer + SIZE ) {
return false;
}
m_end = m_buffer + m_inputStream.read( m_buffer, SIZE );
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

@ -1,159 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_BYTESTREAMUTILS_H )
#define INCLUDED_BYTESTREAMUTILS_H
#include "globaldefs.h"
#if GDEF_COMPILER_GNU
#define _ISOC9X_SOURCE 1
#define _ISOC99_SOURCE 1
#define __USE_ISOC9X 1
#define __USE_ISOC99 1
#include <stdint.h>
#endif
#include <algorithm>
// if C99 is unavailable, fall back to the types most likely to be the right sizes
#if !defined( int16_t )
typedef signed short int16_t;
#endif
#if !defined( uint16_t )
typedef unsigned short uint16_t;
#endif
#if !defined( int32_t )
typedef signed int int32_t;
#endif
#if !defined( uint32_t )
typedef unsigned int uint32_t;
#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 (GDEF_ARCH_ENDIAN_BIG) {
std::reverse(reinterpret_cast<typename InputStreamType::byte_type *>( &value ),
reinterpret_cast<typename InputStreamType::byte_type *>( &value ) + sizeof(Type));
}
}
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 (!GDEF_ARCH_ENDIAN_BIG) {
std::reverse(reinterpret_cast<typename InputStreamType::byte_type *>( &value ),
reinterpret_cast<typename InputStreamType::byte_type *>( &value ) + sizeof(Type));
}
}
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 int16_t istream_read_int16_be( InputStreamType& istream ){
int16_t value;
istream_read_big_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 uint16_t istream_read_uint16_be( InputStreamType& istream ){
uint16_t value;
istream_read_big_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 int32_t istream_read_int32_be( InputStreamType& istream ){
int32_t value;
istream_read_big_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 uint32_t istream_read_uint32_be( InputStreamType& istream ){
uint32_t value;
istream_read_big_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 float istream_read_float32_be( InputStreamType& istream ){
float value;
istream_read_big_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

@ -1,44 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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

View file

@ -1,101 +0,0 @@
/*
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
//
// start of shared cmdlib stuff
//
#ifndef __CMDLIB__
#define __CMDLIB__
#include "globaldefs.h"
#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, bool waitfor );
// 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
#if GDEF_OS_WINDOWS
#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

@ -1,20 +0,0 @@
# WorldSpawn Makefile
LIB_CFLAGS=$(CFLAGS) -I../../include -I../../libs
DO_CXX=$(CXX) -static -fPIC $(LIB_CFLAGS) -o $@ -c $<
.cpp.o:
$(DO_CXX)
WS_OBJS = \
cmdlib.o
# binary target
../libcmdlib.a: $(WS_OBJS)
ar rcs $@ $(WS_OBJS)
# object files
cmdlib.o: cmdlib.cpp
clean:
-rm -f *.o ../libcmdlib.a

View file

@ -1,138 +0,0 @@
/*
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
//
// start of shared cmdlib stuff
//
#include "cmdlib.h"
#include "globaldefs.h"
#include <string.h>
#include <stdio.h>
#include "string/string.h"
#include "os/path.h"
#include "container/array.h"
#if GDEF_OS_POSIX
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
bool Q_Exec( const char *cmd, char *cmdline, const char *, bool, bool waitfor ){
char fullcmd[2048];
char *pCmd;
pid_t pid;
#if GDEF_DEBUG
printf( "Q_Exec damnit\n" );
#endif
switch ( ( pid = fork() ) )
{
default:
if ( waitfor ) {
waitpid( pid, NULL, 0 );
}
break;
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++;
#if GDEF_DEBUG
printf( "Running system...\n" );
printf( "Command: %s\n", pCmd );
#endif
system( pCmd );
#if GDEF_DEBUG
printf( "system() returned\n" );
#endif
_exit( 0 );
break;
}
return true;
}
#elif GDEF_OS_WINDOWS
#include <windows.h>
// NOTE TTimo windows is VERY nitpicky about the syntax in CreateProcess
bool Q_Exec( const char *cmd, char *cmdline, const char *execdir, bool bCreateConsole, bool waitfor ){
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
) ) {
if ( waitfor ) {
WaitForSingleObject( ProcessInformation.hProcess, INFINITE );
}
return true;
}
return false;
}
#endif

View file

@ -1,21 +0,0 @@
# WorldSpawn Makefile
LIB_CFLAGS=$(CFLAGS) -I../../include -I../../libs
DO_CXX=$(CXX) -static -fPIC $(LIB_CFLAGS) -o $@ -c $<
.cpp.o:
$(DO_CXX)
WS_OBJS = \
array.o hashtable.o
# binary target
../libcontainer.a: $(WS_OBJS)
ar rcs $@ $(WS_OBJS)
# object files
array.o: array.cpp array.h cache.h container.h hashfunc.h
hashtable.o: hashtable.cpp hashtable.h stack.h
clean:
-rm -f *.o ../libcontainer.a

View file

@ -1,37 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "array.h"
namespace
{
class Bleh
{
Array<int> m_array;
public:
Bleh() : m_array( 16 ){
}
};
void testAutoArray(){
Array<Bleh> array( 32 );
}
}

View file

@ -1,170 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_CONTAINER_ARRAY_H )
#define INCLUDED_CONTAINER_ARRAY_H
#include "globaldefs.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 ){
if ( other.size() == size() ) {
std::copy( other.begin(), other.end(), begin() );
}
else
{
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 GDEF_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 GDEF_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

@ -1,178 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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.
/// \param CreationPolicy Must define 'Cached* construct(const Key&)' and 'void destroy(Cached*)'. The lifetime of the \c Key passed to 'construct' is guaranteed to be longer than the subsequent matched call to 'destroy'.
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 ){
#if 0
Element& elem = m_map[key];
if ( elem.increment() == 1 ) {
elem.set( CreationPolicy::construct( key ) );
}
return elem;
#else
iterator i = m_map.insert( key, Element() );
if ( ( *i ).value.increment() == 1 ) {
( *i ).value.set( CreationPolicy::construct( ( *i ).key ) );
}
return ( *i ).value;
#endif
}
#else
value_type& capture( const Key& key ){
iterator i = m_map.find( key );
if ( i == m_map.end() ) {
i = m_map.insert( key, Element() );
( *i ).value.set( CreationPolicy::construct( ( *i ).key ) );
}
( *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

@ -1,330 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_CONTAINER_CONTAINER_H )
#define INCLUDED_CONTAINER_CONTAINER_H
#include <algorithm>
#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 );
}
}
template<typename Type>
class ReferencePair
{
Type* m_first;
Type* m_second;
public:
ReferencePair() : m_first( 0 ), m_second( 0 ){
}
void attach( Type& t ){
ASSERT_MESSAGE( m_first == 0 || m_second == 0, "ReferencePair::insert: pointer already exists" );
if ( m_first == 0 ) {
m_first = &t;
}
else if ( m_second == 0 ) {
m_second = &t;
}
}
void detach( Type& t ){
ASSERT_MESSAGE( m_first == &t || m_second == &t, "ReferencePair::erase: pointer not found" );
if ( m_first == &t ) {
m_first = 0;
}
else if ( m_second == &t ) {
m_second = 0;
}
}
template<typename Functor>
void forEach( const Functor& functor ){
if ( m_second != 0 ) {
functor( *m_second );
}
if ( m_first != 0 ) {
functor( *m_first );
}
}
};
#endif

View file

@ -1,402 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_CONTAINER_HASHFUNC_H )
#define INCLUDED_CONTAINER_HASHFUNC_H
#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 ) );
}
};
// lookup2.c
// By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
// code any way you wish, private, educational, or commercial. It's free.
#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);
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 RawStringHash
{
typedef hash_t hash_type;
hash_type operator()( const char* string ) const {
return string_hash( string );
}
};
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

@ -1,63 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "hashtable.h"
#include "globaldefs.h"
#if GDEF_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

@ -1,410 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_CONTAINER_HASHTABLE_H )
#define INCLUDED_CONTAINER_HASHTABLE_H
#include <cstddef>
#include <algorithm>
#include <functional>
#include <memory>
#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() const {
return static_cast<BucketNode*>( next );
}
BucketNode* getPrev() const {
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*() const {
return m_node->m_value;
}
value_type* operator->() const {
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.
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 ) {
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

@ -1,211 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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

@ -1,266 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_CONVERT_H )
#define INCLUDED_CONVERT_H
/// \file
/// \brief Character encoding conversion.
#include "debugging/debugging.h"
#include <algorithm>
#include <glib.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;
gsize inbytesleft = 1;
char* outbuf = m_converted[i];
gsize 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.first; p != convert.m_range.last; )
{
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.first; p != convert.m_range.last; ++p )
{
if ( !char_is_ascii( *p ) ) {
UTF8Character c( globalExtendedASCIICharacterSet().decode( *p ) );
ostream.write( c.buffer, c.length );
}
else
{
ostream << *p;
}
}
return ostream;
}
#endif

View file

@ -1,20 +0,0 @@
# WorldSpawn Makefile
LIB_CFLAGS=$(CFLAGS) -I../../include -I../../libs
DO_CXX=$(CXX) -static -fPIC $(LIB_CFLAGS) -o $@ -c $<
.cpp.o:
$(DO_CXX)
WS_OBJS = \
debugging.o
# binary target
../libdebugging.a: $(WS_OBJS)
ar rcs $@ $(WS_OBJS)
# object files
debugging.o: debugging.cpp debugging.h
clean:
-rm -f *.o ../libdebugging.a

View file

@ -1,27 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "debugging.h"
void TEST_ASSERT(){
ERROR_MESSAGE( "test" );
ASSERT_NOTNULL( 0 );
}

View file

@ -1,129 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_DEBUGGING_DEBUGGING_H )
#define INCLUDED_DEBUGGING_DEBUGGING_H
/// \file
/// \brief Debugging macros for fatal error/assert messages.
#include "globaldefs.h"
#include "stream/textstream.h"
#include "warnings.h"
#include "generic/static.h"
#if GDEF_COMPILER_MSVC && ( defined( _M_IX86 ) || defined( _M_AMD64 ) )
#define DEBUGGER_BREAKPOINT() __asm { int 3 }
#elif GDEF_COMPILER_GNU && __GNUC__ >= 2 && ( defined ( __i386__ ) || defined ( __x86_64__ ) )
#define DEBUGGER_BREAKPOINT() __asm__ __volatile__ ( "int $03" )
#else
#include <signal.h>
#define DEBUGGER_BREAKPOINT() raise( SIGTRAP );
#endif
#define STR( x ) #x
#define STR2( x ) STR( x )
#define FILE_LINE __FILE__ ":" STR2( __LINE__ )
#define DEBUG_ASSERTS
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 GDEF_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 ) do { \
if ( !( condition ) ) \
{ \
globalDebugMessageHandler().getOutputStream() << FILE_LINE "\nassertion failure: " << message << "\n"; \
if ( !globalDebugMessageHandler().handleMessage() ) { DEBUGGER_BREAKPOINT(); } \
}} while ( 0 )
/// \brief Sends a \p message to the current debug-message-handler text-output-stream.
#define ERROR_MESSAGE( message ) do { \
globalDebugMessageHandler().getOutputStream() << FILE_LINE "\nruntime error: " << message << "\n"; \
if ( !globalDebugMessageHandler().handleMessage() ) { DEBUGGER_BREAKPOINT(); }} while ( 0 )
#define ASSERT_NOTNULL( ptr ) ASSERT_MESSAGE( ptr != 0, "pointer \"" #ptr "\" is null" )
#define ASSERT_TRUE( flag ) ASSERT_MESSAGE( !!(flag) == true, "condition \"" #flag "\" is false" )
#else
#define ASSERT_MESSAGE( condition, message )
#define ERROR_MESSAGE( message )
#define ASSERT_NOTNULL( ptr )
#endif
#endif

View file

@ -1,228 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_DRAGPLANES_H )
#define INCLUDED_DRAGPLANES_H
#include "selectable.h"
#include "selectionlib.h"
#include "math/aabb.h"
#include "math/line.h"
// local must be a pure rotation
inline Vector3 translation_to_local( const Vector3& translation, const Matrix4& local ){
return matrix4_get_translation_vec3(
matrix4_multiplied_by_matrix4(
matrix4_translated_by_vec3( matrix4_transposed( local ), translation ),
local
)
);
}
// local must be a pure rotation
inline Vector3 translation_from_local( const Vector3& translation, const Matrix4& local ){
return matrix4_get_translation_vec3(
matrix4_multiplied_by_matrix4(
matrix4_translated_by_vec3( local, translation ),
matrix4_transposed( local )
)
);
}
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
AABB m_bounds;
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, const Matrix4& rotation = g_matrix4_identity ){
Line line( test.getNear(), test.getFar() );
Vector3 corners[8];
aabb_corners_oriented( aabb, rotation, corners );
Plane3 planes[6];
aabb_planes_oriented( aabb, rotation, 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 );
selectedPlaneCallback( planes[5] );
//globalOutputStream() << "bottom\n";
}
m_bounds = aabb;
}
void selectReversedPlanes( const AABB& aabb, Selector& selector, const SelectedPlanes& selectedPlanes, const Matrix4& rotation = g_matrix4_identity ){
Plane3 planes[6];
aabb_planes_oriented( aabb, rotation, 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 );
}
}
AABB evaluateResize( const Vector3& translation ) const {
Vector3 min = m_bounds.origin - m_bounds.extents;
Vector3 max = m_bounds.origin + m_bounds.extents;
if ( m_bounds.extents[0] != 0 ) {
if ( m_selectable_right.isSelected() ) {
max[0] += translation[0];
//globalOutputStream() << "moving right\n";
}
if ( m_selectable_left.isSelected() ) {
min[0] += translation[0];
//globalOutputStream() << "moving left\n";
}
}
if ( m_bounds.extents[1] != 0 ) {
if ( m_selectable_front.isSelected() ) {
max[1] += translation[1];
//globalOutputStream() << "moving front\n";
}
if ( m_selectable_back.isSelected() ) {
min[1] += translation[1];
//globalOutputStream() << "moving back\n";
}
}
if ( m_bounds.extents[2] != 0 ) {
if ( m_selectable_top.isSelected() ) {
max[2] += translation[2];
//globalOutputStream() << "moving top\n";
}
if ( m_selectable_bottom.isSelected() ) {
min[2] += translation[2];
//globalOutputStream() << "moving bottom\n";
}
}
return AABB( vector3_mid( min, max ), vector3_scaled( vector3_subtracted( max, min ), 0.5 ) );
}
AABB evaluateResize( const Vector3& translation, const Matrix4& rotation ) const {
AABB aabb( evaluateResize( translation_to_local( translation, rotation ) ) );
aabb.origin = m_bounds.origin + translation_from_local( aabb.origin - m_bounds.origin, rotation );
return aabb;
}
Matrix4 evaluateTransform( const Vector3& translation ) const {
AABB aabb( evaluateResize( translation ) );
Vector3 scale(
m_bounds.extents[0] != 0 ? aabb.extents[0] / m_bounds.extents[0] : 1,
m_bounds.extents[1] != 0 ? aabb.extents[1] / m_bounds.extents[1] : 1,
m_bounds.extents[2] != 0 ? aabb.extents[2] / m_bounds.extents[2] : 1
);
Matrix4 matrix( matrix4_translation_for_vec3( aabb.origin - m_bounds.origin ) );
matrix4_pivoted_scale_by_vec3( matrix, scale, m_bounds.origin );
return matrix;
}
};
#endif

View file

@ -1,306 +0,0 @@
/*
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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
{
using ListItem = std::pair<CopiedString, CopiedString>;
using ListItems = std::vector<ListItem>;
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

@ -1,718 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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/pooledstring.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_forward, const Vector3& direction_left, const Vector3& direction_up ){
Vector3 endpoint( vector3_added( origin, vector3_scaled( direction_forward, 32.0 ) ) );
Vector3 tip1( vector3_added( vector3_added( endpoint, vector3_scaled( direction_forward, -8.0 ) ), vector3_scaled( direction_up, -4.0 ) ) );
Vector3 tip2( vector3_added( tip1, vector3_scaled( direction_up, 8.0 ) ) );
Vector3 tip3( vector3_added( vector3_added( endpoint, vector3_scaled( direction_forward, -8.0 ) ), vector3_scaled( direction_left, -4.0 ) ) );
Vector3 tip4( vector3_added( tip3, vector3_scaled( direction_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] ){
unsigned int indices[26] = {
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 4, 1, 5, 2, 6, 3, 7,
// 0, 6, 1, 7, 2, 4, 3, 5 // X cross
1, 7 // diagonal line (connect mins to maxs corner)
};
#if 1
glVertexPointer( 3, GL_FLOAT, 0, points );
glDrawElements( GL_LINES, sizeof( indices ) / sizeof( indices[0] ), GL_UNSIGNED_INT, indices );
#else
glBegin( GL_LINES );
for ( std::size_t i = 0; i < sizeof( indices ) / sizeof( indices[0] ); ++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 );
}
};
/// \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 : public EntityKeyValue
{
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 MemberCaller<KeyValue, void (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.
#include "stream/stringstream.h"
class EntityKeyValues : public Entity
{
public:
typedef KeyValue Value;
static StringPool& getPool(){
return Static<StringPool, KeyContext>::instance();
}
private:
static EntityCreator::KeyValueChangedFunc m_entityKeyValueChanged;
static Counter* m_counter;
EntityClass* m_eclass;
class KeyContext {};
typedef Static<StringPool, KeyContext> KeyPool;
typedef PooledString<KeyPool> Key;
typedef SmartPointer<KeyValue> KeyValuePtr;
typedef UnsortedMap<Key, 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() );
}
}
/* see if our key already exists in here */
void insert( const char* key, const char* value ){
int dupecheck = 1;
if (!strncmp(key, "On", 2))
dupecheck = 0;
KeyValues::iterator i = m_keyValues.find( key );
/* does the key already exist */
if (i != m_keyValues.end() ) {
/* re-assign only when we're a special field, else pick a new name */
if (dupecheck) {
( *i ).second->assign( value );
printf("[ENTLIB]: dupe found, setting %s to %s\n", key, value);
} else {
bool b = true;
unsigned int num = 0;
StringOutputStream new_key(64);
/* loop through and generate an enumerated variant */
do {
/* keep incrementing num until we find a free slot */
num++;
new_key.clear();
new_key << key << "#" << Unsigned(num);
i = m_keyValues.find(new_key.c_str());
if (i == m_keyValues.end()) {
insert(new_key.c_str(), value);
b = false;
}
} while (b != false);
}
}
else
{
m_undo.save();
insert( key, KeyValuePtr( new KeyValue( value, EntityClass_valueForKey( *m_eclass, key ) ) ) );
printf("[ENTLIB]: inserting key %s = %s\n", key, value);
}
}
void erase( KeyValues::iterator i ){
if ( m_instanced ) {
( *i ).second->instanceDetach( m_undo.map() );
}
Key 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:
bool m_isContainer;
EntityKeyValues( EntityClass* eclass ) :
m_eclass( eclass ),
m_undo( m_keyValues, UndoImportCaller( *this ) ),
m_instanced( false ),
m_observerMutex( false ),
m_isContainer( !eclass->fixedsize ){
}
EntityKeyValues( const EntityKeyValues& other ) :
Entity( other ),
m_eclass( &other.getEntityClass() ),
m_undo( m_keyValues, UndoImportCaller( *this ) ),
m_instanced( false ),
m_observerMutex( false ),
m_isContainer( other.m_isContainer ){
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(){
for ( Observers::iterator i = m_observers.begin(); i != m_observers.end(); )
{
// post-increment to allow current element to be removed safely
( *i++ )->clear();
}
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 MemberCaller<EntityKeyValues, void (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 );
}
int getKeyEntries( void ) const {
int i = 0;
for ( KeyValues::const_iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i )
{
i++;
}
}
bool isContainer() const {
return m_isContainer;
}
};
/// \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

@ -1,98 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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

@ -1,160 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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( StringRange range )
: m_path( range ), 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() : m_file( 0 ){
}
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;
typedef Entry entry_type;
iterator begin(){
return m_entries.begin();
}
iterator end(){
return m_entries.end();
}
/// \brief Returns the file at \p path.
/// Creates all directories below \p path if they do not exist.
/// O(log n) on average.
entry_type& operator[]( const Path& path ){
{
const char* end = path_remove_directory( path.c_str() );
while ( end[0] != '\0' )
{
Path dir( StringRange( path.c_str(), end ) );
m_entries.insert( value_type( dir, Entry( 0 ) ) );
end = path_remove_directory( end );
}
}
return m_entries[path];
}
/// \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

@ -1,82 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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

@ -1,23 +0,0 @@
# WorldSpawn Makefile
LIB_CFLAGS=$(CFLAGS) -I../../include -I../../libs
DO_CXX=$(CXX) -static -fPIC $(LIB_CFLAGS) -o $@ -c $<
.cpp.o:
$(DO_CXX)
WS_OBJS = \
callback.o constant.o object.o static.o
# binary target
../libgeneric.a: $(WS_OBJS)
ar rcs $@ $(WS_OBJS)
# object files
callback.o: callback.cpp callback.h
constant.o: constant.cpp constant.h
object.o: object.cpp object.h
static.o: static.cpp static.h
clean:
-rm -f *.o ../libgeneric.a

View file

@ -1,70 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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 first, Iterator last )
: first( first ), last( last ){
}
Iterator first;
Iterator last;
};
template<typename Element>
inline ArrayRange<Element> makeArrayRange( Element* first, Element* last ){
return ArrayRange<Element>( first, last );
}
template<typename Element>
struct ArrayConstRange
{
typedef const Element* Iterator;
ArrayConstRange( Iterator first, Iterator last )
: first( first ), last( last ){
}
Iterator first;
Iterator last;
};
template<typename Element>
inline ArrayConstRange<Element> makeArrayRange( const Element* first, const Element* last ){
return ArrayConstRange<Element>( first, last );
}
#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 ) ) )
typedef ArrayRange<const char> StringRange;
#endif

View file

@ -1,115 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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

@ -1,255 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "callback.h"
#include "globaldefs.h"
#if GDEF_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, void (), &Integer::setValue> SetValueCaller;
};
void example(){
Integer foo = { 0 };
{
Callback<void()> bar = ConstMemberCaller<Integer, void(), &Integer::printValue>( foo );
// invoke the callback
bar(); // foo.printValue()
}
{
// use the typedef to improve readability
Callback<void()> 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, void (), Int_setValue> IntSetValueCaller;
void example(){
int foo = 0;
{
Callback<void()> bar = ConstReferenceCaller<int, void(), Int_printValue>( foo );
// invoke the callback
bar(); // Int_printValue(foo)
}
{
// use the typedef to improve readability
Callback<void()> bar = IntSetValueCaller( foo );
// invoke the callback
bar(); // Int_setValue(foo)
}
}
// end example
}
#endif
namespace
{
class A1
{
};
class A2
{
};
class A3
{
};
class A4
{
};
class Test
{
public:
void test0(){
}
typedef Member<Test, void (), &Test::test0> Test0;
typedef MemberCaller<Test, void (), &Test::test0> Test0Caller;
void test0const() const {
}
typedef ConstMember<Test, void (), &Test::test0const> Test0Const;
typedef ConstMemberCaller<Test, void (), &Test::test0const> Test0ConstCaller;
void test1( A1 ){
}
typedef Member<Test, void (A1), &Test::test1> Test1;
typedef MemberCaller<Test, void (A1), &Test::test1> Test1Caller;
void test1const( A1 ) const {
}
typedef ConstMember<Test, void (A1), &Test::test1const> Test1Const;
typedef ConstMemberCaller<Test, void (A1), &Test::test1const> Test1ConstCaller;
void test2( A1, A2 ){
}
typedef Member<Test, void (A1, A2), &Test::test2> Test2;
void test2const( A1, A2 ) const {
}
typedef ConstMember<Test, void (A1, A2), &Test::test2const> Test2Const;
void test3( A1, A2, A3 ){
}
typedef Member<Test, void (A1, A2, A3), &Test::test3> Test3;
void test3const( A1, A2, A3 ) const {
}
typedef ConstMember<Test, void (A1, A2, A3), &Test::test3const> Test3Const;
};
void test0free(){
}
void test1free( A1 ){
}
void test2free( A1, A2 ){
}
typedef Function<void (A1, A2), &test2free> Test2Free;
void test3free( A1, A2, A3 ){
}
typedef Function<void (A1, A2, A3), &test3free> Test3Free;
void test0( Test& test ){
}
typedef ReferenceCaller<Test, void (), &test0> Test0Caller;
void test0const( const Test& test ){
}
typedef ConstReferenceCaller<Test, void (), &test0const> Test0ConstCaller;
void test0p( Test* test ){
}
typedef PointerCaller<Test, void (), &test0p> Test0PCaller;
void test0constp( const Test* test ){
}
typedef ConstPointerCaller<Test, void (), &test0constp> Test0ConstPCaller;
void test1( Test& test, A1 ){
}
typedef ReferenceCaller<Test, void (A1), &test1> Test1Caller;
void test1const( const Test& test, A1 ){
}
typedef ConstReferenceCaller<Test, void (A1), &test1const> Test1ConstCaller;
void test1p( Test* test, A1 ){
}
typedef PointerCaller<Test, void (A1), &test1p> Test1PCaller;
void test1constp( const Test* test, A1 ){
}
typedef ConstPointerCaller<Test, void (A1), &test1constp> Test1ConstPCaller;
void test2( Test& test, A1, A2 ){
}
typedef Function<void (Test&, A1, A2), &test2> Test2;
void test3( Test& test, A1, A2, A3 ){
}
typedef Function<void (Test&, A1, A2, A3), &test3> Test3;
void instantiate(){
Test test;
const Test& testconst = test;
{
Callback<void()> a = makeCallbackF(&test0free);
Callback<void()> b = Test::Test0Caller( test );
b = makeCallback( Test::Test0(), test );
Callback<void()> c = Test::Test0ConstCaller( testconst );
c = makeCallback( Test::Test0Const(), test );
Test0Caller{ test };
Test0ConstCaller{ testconst };
Test0PCaller{ &test };
Test0ConstPCaller{ &testconst };
a();
bool u = a != b;
}
{
typedef Callback<void (A1)> TestCallback1;
TestCallback1 a = makeCallbackF(&test1free);
TestCallback1 b = Test::Test1Caller( test );
b = makeCallback( Test::Test1(), test );
TestCallback1 c = Test::Test1ConstCaller( testconst );
c = makeCallback( Test::Test1Const(), test );
Test1Caller{ test };
Test1ConstCaller{ testconst };
Test1PCaller{ &test };
Test1ConstPCaller{ &testconst };
a( A1() );
bool u = a != b;
}
{
typedef Callback<void (A1, A2)> TestCallback2;
TestCallback2 a = makeStatelessCallback( Test2Free() );
TestCallback2 b = makeCallback( Test2(), test );
makeCallback( Test::Test2(), test );
makeCallback( Test::Test2Const(), test );
a( A1(), A2() );
bool u = a != b;
}
{
typedef Callback<void (A1, A2, A3)> TestCallback3;
TestCallback3 a = makeStatelessCallback( Test3Free() );
TestCallback3 b = makeCallback( Test3(), test );
makeCallback( Test::Test3(), test );
makeCallback( Test::Test3Const(), test );
a( A1(), A2(), A3() );
bool u = a != b;
}
}
}

View file

@ -1,349 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_GENERIC_CLOSURE_H )
#define INCLUDED_GENERIC_CLOSURE_H
/// \file
/// \brief Type-safe techniques for binding the first argument of an opaque callback.
#include <cstddef>
#include "functional.h"
namespace detail {
template<typename Thunk_>
class CallbackBase {
void *m_environment;
Thunk_ m_thunk;
public:
typedef Thunk_ Thunk;
CallbackBase(void *environment, Thunk function) : m_environment(environment), m_thunk(function) {
}
void *getEnvironment() const {
return m_environment;
}
Thunk getThunk() const {
return m_thunk;
}
};
template<typename Thunk>
inline bool operator==(const CallbackBase<Thunk> &self, const CallbackBase<Thunk> &other) {
return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk();
}
template<typename Thunk>
inline bool operator!=(const CallbackBase<Thunk> &self, const CallbackBase<Thunk> &other) {
return !(self == other);
}
template<typename Thunk>
inline bool operator<(const CallbackBase<Thunk> &self, const CallbackBase<Thunk> &other) {
return self.getEnvironment() < other.getEnvironment() ||
(!(other.getEnvironment() < self.getEnvironment()) && self.getThunk() < other.getThunk());
}
}
namespace detail {
template<class Type>
struct ConvertFromOpaque {
};
// reference
template<class T>
inline const void *convertToOpaque(const T &t) {
return &t;
}
template<class T>
struct ConvertFromOpaque<const T &> {
static T const &apply(void *p) {
return *static_cast<const T *>(p);
}
};
template<class T>
inline void *convertToOpaque(T &t) {
return &t;
}
template<class T>
struct ConvertFromOpaque<T &> {
static T &apply(void *p) {
return *static_cast<T *>( p );
}
};
// pointer
template<class T, class U = typename std::enable_if<!std::is_function<T>::value>::type>
inline const void *convertToOpaque(const T *t) {
return t;
}
template<class T>
struct ConvertFromOpaque<const T *> {
static const T *apply(void *p) {
return static_cast<const T *>(p);
}
};
template<class T, class U = typename std::enable_if<!std::is_function<T>::value>::type>
inline void *convertToOpaque(T *t) {
return t;
}
template<class T>
struct ConvertFromOpaque<T *> {
static T *apply(void *p) {
return static_cast<T *>(p);
}
};
// function pointer
template<class R, class... Ts>
inline const void *convertToOpaque(R(*const &t)(Ts ...)) {
return &t;
}
template<class R, class ... Ts>
struct ConvertFromOpaque<R(*const &)(Ts...)> {
using Type = R (*)(Ts...);
static Type const &apply(void *p) {
return *static_cast<Type *>(p);
}
};
template<class R, class... Ts>
inline void *convertToOpaque(R(*&t)(Ts ...)) {
return &t;
}
template<class R, class ... Ts>
struct ConvertFromOpaque<R(*&)(Ts...)> {
using Type = R (*)(Ts...);
static Type &apply(void *p) {
return *static_cast<Type *>(p);
}
};
template<class Caller, class F>
class BindFirstOpaqueN;
template<class Caller, class R, class FirstBound, class ... Ts>
class BindFirstOpaqueN<Caller, R(FirstBound, Ts...)> {
FirstBound firstBound;
public:
explicit BindFirstOpaqueN(FirstBound firstBound) : firstBound(firstBound) {
}
R operator()(Ts... args) const {
return Caller::call(firstBound, args ...);
}
FirstBound getBound() const {
return firstBound;
}
static R thunk(void *environment, Ts... args) {
return thunk_(detail::ConvertFromOpaque<FirstBound>::apply(environment), args ...);
}
static R thunk_(FirstBound environment, Ts... args) {
return Caller::call(environment, args ...);
}
void *getEnvironment() const {
return const_cast<void *>(detail::convertToOpaque(firstBound));
}
};
}
template<class Caller>
using BindFirstOpaque = detail::BindFirstOpaqueN<Caller, get_func<Caller> >;
/// \brief Combines a void pointer with a pointer to a function which operates on a void pointer.
///
/// Use with the callback constructors MemberCaller0, ConstMemberCaller0, ReferenceCaller0, ConstReferenceCaller0, PointerCaller0, ConstPointerCaller0 and FreeCaller0.
template<class F>
class Callback;
template<class R, class ... Ts>
class Callback<R(Ts...)> : public detail::CallbackBase<R (*)(void *, Ts...)> {
using Base = detail::CallbackBase<R (*)(void *, Ts...)>;
static R nullThunk(void *, Ts...) {
}
public:
using func = R(Ts ...);
Callback() : Base(0, nullThunk) {
}
template<typename Caller>
Callback(const BindFirstOpaque<Caller> &caller) : Base(caller.getEnvironment(), BindFirstOpaque<Caller>::thunk) {
}
Callback(void *environment, typename Base::Thunk function) : Base(environment, function) {
}
R operator()(Ts... args) const {
return Base::getThunk()(Base::getEnvironment(), args ...);
}
};
namespace detail {
template<class F>
struct Arglist;
template<class R, class Head, class ... Ts>
struct Arglist<R(Head, Ts...)> {
using type = R(Head, Ts ...);
template <class Unshift>
using unshift = Arglist<R(Unshift, Head, Ts...)>;
using shift = Arglist<R(Ts...)>;
};
template<class R, class ... Ts>
struct Arglist<R(Ts...)> {
using type = R(Ts ...);
template <class Unshift>
using unshift = Arglist<R(Unshift, Ts...)>;
};
template<class F>
using ArgShift = typename detail::Arglist<F>::shift::type;
template<class F, class T>
using ArgUnshift = typename detail::Arglist<F>::template unshift<T>::type;
}
template<typename Caller>
inline Callback<detail::ArgShift<get_func<Caller> > > makeCallback(const Caller &caller, get_argument<Caller, 0> callee) {
return BindFirstOpaque<Caller>(callee);
}
template<class Caller, class F>
class CallerShiftFirst;
template<class Caller, class R, class FirstArgument, class ... Ts>
class CallerShiftFirst<Caller, R(FirstArgument, Ts...)> {
public:
using func = R(FirstArgument, Ts ...);
static R call(FirstArgument, Ts... args) {
return Caller::call(args ...);
}
};
template<typename Caller>
inline Callback<get_func<Caller> > makeStatelessCallback(const Caller &caller) {
return makeCallback(CallerShiftFirst<Caller, detail::ArgUnshift<get_func<Caller>, void *> >(), nullptr);
}
/// \brief Forms a Callback from a non-const Environment reference and a non-const Environment member-function.
template<class Environment, class F, MemberFunction<Environment, F> member>
using MemberCaller = BindFirstOpaque<Member<Environment, F, member> >;
/// \brief Constructs a Callback1 from a non-const \p functor
///
/// \param Functor Must define \c first_argument_type and \c operator()(first_argument_type).
template<typename Functor>
inline Callback<get_func<Functor> > makeCallback(Functor &functor) {
return MemberCaller<Functor, get_func<Functor>, &Functor::operator()>(functor);
}
/// \brief Forms a Callback from a const Environment reference and a const Environment member-function.
template<class Environment, class F, ConstMemberFunction<Environment, F> member>
using ConstMemberCaller = BindFirstOpaque<ConstMember<Environment, F, member> >;
/// \brief Constructs a Callback1 from a const \p functor
///
/// \param Functor Must define \c first_argument_type and const \c operator()(first_argument_type).
template<typename Functor>
inline Callback<get_func<Functor> > makeCallback(const Functor &functor) {
return ConstMemberCaller<Functor, get_func<Functor>, &Functor::operator()>(functor);
}
/// \brief Forms a Callback from a non-const Environment reference and a free function which operates on a non-const Environment reference.
template<class Environment, class F, detail::ArgUnshift<F, Environment &> *func>
using ReferenceCaller = BindFirstOpaque<Function<detail::ArgUnshift<F, Environment &>, func> >;
/// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference.
template<class Environment, class F, detail::ArgUnshift<F, const Environment &> *func>
using ConstReferenceCaller = BindFirstOpaque<Function<detail::ArgUnshift<F, const Environment &>, func> >;
/// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer.
template<class Environment, class F, detail::ArgUnshift<F, Environment *> *func>
using PointerCaller = BindFirstOpaque<Function<detail::ArgUnshift<F, Environment *>, func> >;
/// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer.
template<class Environment, class F, detail::ArgUnshift<F, const Environment *> *func>
using ConstPointerCaller = BindFirstOpaque<Function<detail::ArgUnshift<F, const Environment *>, func> >;
namespace detail {
template<class Caller, class F>
class FreeCaller : public BindFirstOpaque<CallerShiftFirst<Caller, detail::ArgUnshift<F, void *> > > {
public:
FreeCaller() : BindFirstOpaque<CallerShiftFirst<Caller, detail::ArgUnshift<F, void *> > >(nullptr) {
}
};
template<class F>
struct FreeCallerWrapper;
template<class R, class ... Ts>
struct FreeCallerWrapper<R(Ts...)> {
using func = R(void *, Ts ...);
static R call(void *f, Ts... args) {
// ideally, we'd get the implementation of the function type directly. Instead, it's passed in
return reinterpret_cast<R (*)(Ts...)>(f)(args ...);
}
};
}
/// \brief Forms a Callback from a free function
template<class F, F *func>
using FreeCaller = detail::FreeCaller<Function<F, func>, F>;
template<class R, class ... Ts>
inline Callback<R(Ts...)> makeCallbackF(R (*func)(Ts...)) {
void *pVoid = reinterpret_cast<void *>(func);
return BindFirstOpaque<detail::FreeCallerWrapper<R(Ts...)> >(pVoid);
}
#endif

View file

@ -1,41 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "constant.h"
#include "globaldefs.h"
#if GDEF_DEBUG || defined( DOXYGEN )
namespace ExampleConstant
{
class Bleh
{
public:
STRING_CONSTANT( Name, "Bleh" );
INTEGER_CONSTANT( Version, 1 );
};
int version = Bleh::Version();
const char* name = Bleh::Name();
}
#endif

View file

@ -1,50 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_GENERIC_CONSTANT_H )
#define INCLUDED_GENERIC_CONSTANT_H
/// \file
/// \brief Language extensions for constants that are guaranteed to be evaluated at compile-time.
/// \brief A compile-time-constant as a type.
template<typename Type>
struct ConstantWrapper
{
typedef typename Type::Value Value;
operator Value() const
{
return Type::evaluate();
}
};
template<typename TextOutputStreamType, typename Type>
inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const ConstantWrapper<Type>& c ){
return ostream_write( ostream, typename Type::Value( c ) );
}
#define TYPE_CONSTANT( name, value, type ) struct name ## _CONSTANT_ { typedef type Value; static Value evaluate() { return value; } }; typedef ConstantWrapper<name ## _CONSTANT_> name
#define STRING_CONSTANT( name, value ) TYPE_CONSTANT ( name, value, const char* )
#define INTEGER_CONSTANT( name, value ) TYPE_CONSTANT ( name, value, int )
#define UINT_CONSTANT( name, value ) TYPE_CONSTANT ( name, value, unsigned int )
STRING_CONSTANT( EmptyString, "" );
#endif

View file

@ -1,56 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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

@ -1,214 +0,0 @@
#if !defined( INCLUDED_FUNCTIONAL_H )
#define INCLUDED_FUNCTIONAL_H
#include <functional>
#include <tuple>
namespace detail {
template<int N>
struct rank : rank<N - 1> {
};
template<>
struct rank<0> {
};
struct get_func {
template<class T>
struct wrapper {
using type = T;
};
template<class F>
using func_member = wrapper<typename F::func>;
template<class F>
static wrapper<func_member<F> > test(rank<2>) {
return {};
}
template<class F>
struct func_lambda {
using type = typename func_lambda<decltype(&F::operator())>::type;
};
template<class R, class ... Ts>
struct func_lambda<R (*)(Ts...)> {
using type = R(Ts ...);
};
template<class Object, class R, class ... Ts>
struct func_lambda<R (Object::*)(Ts...) const> {
using type = R(Ts ...);
};
template<class Object, class R, class ... Ts>
struct func_lambda<R (Object::*)(Ts...)> {
using type = R(Ts ...);
};
template<class F, class = func_lambda<F> >
static wrapper<func_lambda<F> > test(rank<1>) {
return {};
}
};
template<class F>
struct Fn;
template<class R, class ... Ts>
struct Fn<R(Ts...)> {
using result_type = R;
template<int N>
using get = typename std::tuple_element<N, std::tuple<Ts...> >::type;
};
}
template<class Caller>
using get_func = typename decltype(detail::get_func::test<Caller>(detail::rank<2>{}))::type::type;
template<class Caller>
using get_result_type = typename detail::Fn<get_func<Caller> >::result_type;
template<class Caller, int N>
using get_argument = typename detail::Fn<get_func<Caller> >::template get<N>;
namespace detail {
template<class F>
class FunctionN;
template<class R, class ... Ts>
class FunctionN<R(Ts...)> {
public:
template<R(*f)(Ts...)>
class instance {
public:
using func = R(Ts ...);
static R call(Ts... args) {
return (f)(args ...);
}
};
};
}
template<class F, F *func>
using Function = typename detail::FunctionN<F>::template instance<func>;
namespace detail {
template<class Object, class F>
struct MemberFunction;
template<class Object, class R, class ... Ts>
struct MemberFunction<Object, R(Ts...)> {
using type = R (Object::*)(Ts...);
using type_const = R (Object::*)(Ts...) const;
};
}
namespace detail {
template<class Object, class F>
class MemberN;
template<class Object, class R, class ... Ts>
class MemberN<Object, R(Ts...)> {
public:
template<R(Object::*f)(Ts...)>
class instance {
public:
using func = R(Object &, Ts ...);
static R call(Object &object, Ts... args) {
return (object.*f)(args ...);
}
};
};
}
template<class Object, class F>
using MemberFunction = typename detail::MemberFunction<Object, F>::type;
template<class Object, class F, MemberFunction<Object, F> func>
using Member = typename detail::MemberN<Object, F>::template instance<func>;
namespace detail {
template<class Object, class F>
class ConstMemberN;
template<class Object, class R, class ... Ts>
class ConstMemberN<Object, R(Ts...)> {
public:
template<R(Object::*f)(Ts...) const>
class instance {
public:
using func = R(const Object &, Ts ...);
static R call(const Object &object, Ts... args) {
return (object.*f)(args ...);
}
};
};
}
template<class Object, class F>
using ConstMemberFunction = typename detail::MemberFunction<Object, F>::type_const;
template<class Object, class F, ConstMemberFunction<Object, F> func>
using ConstMember = typename detail::ConstMemberN<Object, F>::template instance<func>;
// misc
namespace detail {
template<int ...>
struct seq {
};
template<int N, int... S>
struct gens : gens<N - 1, N - 1, S...> {
};
template<int... S>
struct gens<0, S...> {
using type = seq<S...>;
};
template<int N>
using seq_new = typename gens<N>::type;
template<class Functor, class F>
class FunctorNInvoke;
template<class Functor, class R, class ... Ts>
class FunctorNInvoke<Functor, R(Ts...)> {
std::tuple<Ts...> args;
template<class T>
struct caller;
template<int ... I>
struct caller<seq<I...> > {
static inline R call(FunctorNInvoke<Functor, R(Ts...)> *self, Functor functor) {
(void) self;
return functor(std::get<I>(self->args)...);
}
};
public:
FunctorNInvoke(Ts... args) : args(args ...) {
}
inline R operator()(Functor functor) {
return caller<seq_new<sizeof...(Ts)> >::call(this, functor);
}
};
}
template<class Functor>
using FunctorInvoke = detail::FunctorNInvoke<Functor, get_func<Functor> >;
#endif

View file

@ -1,39 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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

@ -1,90 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_GENERIC_OBJECT_H )
#define INCLUDED_GENERIC_OBJECT_H
#include "globaldefs.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 GDEF_COMPILER_MSVC && _MSC_VER > 1000
#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

@ -1,103 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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 ){
}
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 ){
}
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

@ -1,180 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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

@ -1,125 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "static.h"
#include "globaldefs.h"
#if GDEF_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

@ -1,140 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_GENERIC_STATIC_H )
#define INCLUDED_GENERIC_STATIC_H
/// \file
/// \brief Template techniques for instantiating singletons.
#include <cstddef>
class Null
{
};
/// \brief A singleton which is statically initialised.
///
/// \param Type The singleton object type.
/// \param Type The type distinguishing this instance from others of the same type.
///
/// \dontinclude generic/static.cpp
/// \skipline Static example
/// \until end example
template<typename Type, typename Context = Null>
class Static
{
static Type m_instance;
public:
static Type& instance(){
return m_instance;
}
};
template<typename Type, typename Context>
Type Static<Type, Context>::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.
/// \param Type The type distinguishing this instance from others of the same type.
///
/// \dontinclude generic/static.cpp
/// \skipline LazyStatic example
/// \until end example
template<typename Type, typename Context = Null>
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, typename Context>
Type * LazyStatic<Type, Context>::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.
/// \param Type The type distinguishing this instance from others of the same type.
template<typename Type, typename Context = Null>
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, typename Context>
std::size_t CountedStatic<Type, Context>::m_refcount; // this will be initialised to 0 by the CRT, according to the c++ standard
template<typename Type, typename Context>
Type * CountedStatic<Type, Context>::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.
/// \param Type The type distinguishing this instance from others of the same type.
///
/// \dontinclude generic/static.cpp
/// \skipline SmartStatic example
/// \until end example
template<typename Type, typename Context = Null>
class SmartStatic
{
public:
SmartStatic(){
CountedStatic<Type, Context>::capture();
}
~SmartStatic(){
CountedStatic<Type, Context>::release();
}
Type& instance(){
return CountedStatic<Type, Context>::instance();
}
};
#endif

View file

@ -1,212 +0,0 @@
#if !defined( INCLUDED_VECTOR_H )
#define INCLUDED_VECTOR_H
#include <cstddef>
template <typename Element>
class BasicVector2
{
Element m_elements[2];
public:
BasicVector2(){
}
BasicVector2( const Element& x_, const Element& y_ ){
x() = x_;
y() = y_;
}
Element& x(){
return m_elements[0];
}
const Element& x() const {
return m_elements[0];
}
Element& y(){
return m_elements[1];
}
const Element& y() const {
return m_elements[1];
}
const Element& operator[]( std::size_t i ) const {
return m_elements[i];
}
Element& operator[]( std::size_t i ){
return m_elements[i];
}
Element* data(){
return m_elements;
}
const Element* data() const {
return m_elements;
}
};
/// \brief A 3-element vector.
template<typename Element>
class BasicVector3
{
Element m_elements[3];
public:
BasicVector3(){
}
template<typename OtherElement>
BasicVector3( const BasicVector3<OtherElement>& other ){
x() = static_cast<Element>( other.x() );
y() = static_cast<Element>( other.y() );
z() = static_cast<Element>( other.z() );
}
BasicVector3( const Element& x_, const Element& y_, const Element& z_ ){
x() = x_;
y() = y_;
z() = z_;
}
Element& x(){
return m_elements[0];
}
const Element& x() const {
return m_elements[0];
}
Element& y(){
return m_elements[1];
}
const Element& y() const {
return m_elements[1];
}
Element& z(){
return m_elements[2];
}
const Element& z() const {
return m_elements[2];
}
const Element& operator[]( std::size_t i ) const {
return m_elements[i];
}
Element& operator[]( std::size_t i ){
return m_elements[i];
}
Element* data(){
return m_elements;
}
const Element* data() const {
return m_elements;
}
};
/// \brief A 4-element vector.
template<typename Element>
class BasicVector4
{
Element m_elements[4];
public:
BasicVector4(){
}
BasicVector4( Element x_, Element y_, Element z_, Element w_ ){
x() = x_;
y() = y_;
z() = z_;
w() = w_;
}
BasicVector4( const BasicVector3<Element>& self, Element w_ ){
x() = self.x();
y() = self.y();
z() = self.z();
w() = w_;
}
Element& x(){
return m_elements[0];
}
const Element& x() const {
return m_elements[0];
}
Element& y(){
return m_elements[1];
}
const Element& y() const {
return m_elements[1];
}
Element& z(){
return m_elements[2];
}
const Element& z() const {
return m_elements[2];
}
Element& w(){
return m_elements[3];
}
const Element& w() const {
return m_elements[3];
}
Element index( std::size_t i ) const {
return m_elements[i];
}
Element& index( std::size_t i ){
return m_elements[i];
}
Element operator[]( std::size_t i ) const {
return m_elements[i];
}
Element& operator[]( std::size_t i ){
return m_elements[i];
}
Element* data(){
return m_elements;
}
const Element* data() const {
return m_elements;
}
};
template<typename Element>
inline BasicVector3<Element> vector3_from_array( const Element* array ){
return BasicVector3<Element>( array[0], array[1], array[2] );
}
template<typename Element>
inline Element* vector3_to_array( BasicVector3<Element>& self ){
return self.data();
}
template<typename Element>
inline const Element* vector3_to_array( const BasicVector3<Element>& self ){
return self.data();
}
template<typename Element>
inline Element* vector4_to_array( BasicVector4<Element>& self ){
return self.data();
}
template<typename Element>
inline const Element* vector4_to_array( const BasicVector4<Element>& self ){
return self.data();
}
template<typename Element>
inline BasicVector3<Element>& vector4_to_vector3( BasicVector4<Element>& self ){
return *reinterpret_cast<BasicVector3<Element>*>( vector4_to_array( self ) );
}
template<typename Element>
inline const BasicVector3<Element>& vector4_to_vector3( const BasicVector4<Element>& self ){
return *reinterpret_cast<const BasicVector3<Element>*>( vector4_to_array( self ) );
}
/// \brief A 2-element vector stored in single-precision floating-point.
typedef BasicVector2<float> Vector2;
/// \brief A 3-element vector stored in single-precision floating-point.
typedef BasicVector3<float> Vector3;
/// \brief A 4-element vector stored in single-precision floating-point.
typedef BasicVector4<float> Vector4;
#endif

View file

@ -1,60 +0,0 @@
# WorldSpawn Makefile
GTK_CFLAGS=$(shell pkg-config --cflags gtk+-2.0)
GLEXT_CFLAGS=$(shell pkg-config --cflags gtkglext-1.0)
GLIB_CFLAGS=$(shell pkg-config --cflags glib-2.0)
LIB_CFLAGS=$(CFLAGS) $(GLIB_CFLAGS) $(GTK_CFLAGS) $(GLEXT_CFLAGS) -I../../include -I../../libs -DGTK_TARGET=2
DO_CXX=$(CXX) -static -fPIC $(LIB_CFLAGS) -o $@ -c $<
.cpp.o:
$(DO_CXX)
WS_OBJS = \
accelerator.o \
button.o \
clipboard.o \
cursor.o \
dialog.o \
entry.o \
filechooser.o \
frame.o \
glfont.o \
glwidget.o \
image.o \
menu.o \
messagebox.o \
nonmodal.o \
paned.o \
toolbar.o \
widget.o \
window.o \
xorrectangle.o
# binary target
../libgtkutil.a: $(WS_OBJS)
ar rcs $@ $(WS_OBJS)
# object files
accelerator.o: accelerator.cpp accelerator.h
button.o: button.cpp button.h
clipboard.o: clipboard.cpp clipboard.h
cursor.o: cursor.cpp cursor.h
dialog.o: dialog.cpp dialog.h
entry.o: entry.cpp entry.h
filechooser.o: filechooser.cpp filechooser.h
frame.o: frame.cpp frame.h
glfont.o: glfont.cpp glfont.h
glwidget.o: glwidget.cpp glwidget.h
image.o: image.cpp image.h
menu.o: menu.cpp menu.h
messagebox.o: messagebox.cpp messagebox.h
nonmodal.o: nonmodal.cpp nonmodal.h
paned.o: paned.cpp paned.h
toolbar.o: toolbar.cpp toolbar.h
widget.o: widget.cpp widget.h
window.o: window.cpp window.h
xorrectangle.o: xorrectangle.cpp xorrectangle.h
clean:
-rm -f *.o ../libgtkutil.a

View file

@ -1,609 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "accelerator.h"
#include "debugging/debugging.h"
#include <map>
#include <set>
#include <gtk/gtk.h>
#include "generic/callback.h"
#include "generic/bitfield.h"
#include "string/string.h"
#include "pointer.h"
#include "closure.h"
#include <gdk/gdkkeysyms.h>
const char *global_keys_find(unsigned int key)
{
const char *s;
if (key == 0) {
return "";
}
s = gdk_keyval_name(key);
if (!s) {
return "";
}
return s;
}
unsigned int global_keys_find(const char *name)
{
guint k;
if (!name || !*name) {
return 0;
}
k = gdk_keyval_from_name(name);
if (k == GDK_KEY_VoidSymbol) {
return 0;
}
return k;
}
void accelerator_write(const Accelerator &accelerator, TextOutputStream &ostream)
{
#if 0
if ( accelerator.modifiers & GDK_SHIFT_MASK ) {
ostream << "Shift + ";
}
if ( accelerator.modifiers & GDK_MOD1_MASK ) {
ostream << "Alt + ";
}
if ( accelerator.modifiers & GDK_CONTROL_MASK ) {
ostream << "Control + ";
}
const char* keyName = global_keys_find( accelerator.key );
if ( !string_empty( keyName ) ) {
ostream << keyName;
}
else
{
ostream << static_cast<char>( accelerator.key );
}
#endif
ostream << gtk_accelerator_get_label(accelerator.key, accelerator.modifiers);
}
typedef std::map<Accelerator, Callback<void ()> > AcceleratorMap;
typedef std::set<Accelerator> AcceleratorSet;
bool accelerator_map_insert(AcceleratorMap &acceleratorMap, Accelerator accelerator, const Callback<void()> &callback)
{
if (accelerator.key != 0) {
return acceleratorMap.insert(AcceleratorMap::value_type(accelerator, callback)).second;
}
return true;
}
bool accelerator_map_erase(AcceleratorMap &acceleratorMap, Accelerator accelerator)
{
if (accelerator.key != 0) {
AcceleratorMap::iterator i = acceleratorMap.find(accelerator);
if (i == acceleratorMap.end()) {
return false;
}
acceleratorMap.erase(i);
}
return true;
}
Accelerator accelerator_for_event_key(guint keyval, guint state)
{
keyval = gdk_keyval_to_upper(keyval);
if (keyval == GDK_KEY_ISO_Left_Tab) {
keyval = GDK_KEY_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(ui::Window 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(ui::Window 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;
}
GClosure *accel_group_add_accelerator(ui::AccelGroup group, Accelerator accelerator, const Callback<void()> &callback);
void accel_group_remove_accelerator(ui::AccelGroup group, Accelerator accelerator);
AcceleratorMap g_queuedAcceleratorsAdd;
AcceleratorSet g_queuedAcceleratorsRemove;
void globalQueuedAccelerators_add(Accelerator accelerator, const Callback<void()> &callback)
{
if (!g_queuedAcceleratorsAdd.insert(AcceleratorMap::value_type(accelerator, callback)).second) {
globalErrorStream() << "globalQueuedAccelerators_add: accelerator already queued: " << accelerator << "\n";
}
}
void globalQueuedAccelerators_remove(Accelerator accelerator)
{
if (g_queuedAcceleratorsAdd.erase(accelerator) == 0) {
if (!g_queuedAcceleratorsRemove.insert(accelerator).second) {
globalErrorStream() << "globalQueuedAccelerators_remove: accelerator already queued: " << accelerator
<< "\n";
}
}
}
void globalQueuedAccelerators_commit()
{
for (AcceleratorSet::const_iterator i = g_queuedAcceleratorsRemove.begin();
i != g_queuedAcceleratorsRemove.end(); ++i) {
//globalOutputStream() << "removing: " << (*i).first << "\n";
accel_group_remove_accelerator(global_accel, *i);
}
g_queuedAcceleratorsRemove.clear();
for (AcceleratorMap::const_iterator i = g_queuedAcceleratorsAdd.begin(); i != g_queuedAcceleratorsAdd.end(); ++i) {
//globalOutputStream() << "adding: " << (*i).first << "\n";
accel_group_add_accelerator(global_accel, (*i).first, (*i).second);
}
g_queuedAcceleratorsAdd.clear();
}
typedef std::set<ui::Window> 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) {
ui::Window toplevel = *i;
ASSERT_MESSAGE(window_has_accel(toplevel), "ERROR");
ASSERT_MESSAGE(gtk_widget_is_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
}
}
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) {
ui::Window toplevel = *i;
ASSERT_MESSAGE(!window_has_accel(toplevel), "ERROR");
ASSERT_MESSAGE(gtk_widget_is_toplevel(toplevel), "enabling accel for non-toplevel window");
toplevel.add_accel_group(global_accel);
#if 0
globalOutputStream() << reinterpret_cast<unsigned int>( toplevel ) << ": enabled global accelerators\n";
#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(ui::Widget 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(ui::Widget 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(ui::Widget widget, GdkEventFocus *event, PressedButtons *pressed)
{
Buttons_releaseAll(pressed->buttons);
return FALSE;
}
void PressedButtons_connect(PressedButtons &pressedButtons, ui::Widget widget)
{
widget.connect("button_press_event", G_CALLBACK(PressedButtons_button_press), &pressedButtons);
widget.connect("button_release_event", G_CALLBACK(PressedButtons_button_release), &pressedButtons);
widget.connect("focus_out_event", G_CALLBACK(PressedButtons_focus_out), &pressedButtons);
}
PressedButtons g_pressedButtons;
#include <set>
#include <uilib/uilib.h>
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(ui::Widget widget, GdkEventKey *event, PressedKeys *pressedKeys)
{
//globalOutputStream() << "pressed: " << event->keyval << "\n";
return event->state == 0 && Keys_press(pressedKeys->keys, event->keyval);
}
gboolean PressedKeys_key_release(ui::Widget widget, GdkEventKey *event, PressedKeys *pressedKeys)
{
//globalOutputStream() << "released: " << event->keyval << "\n";
return Keys_release(pressedKeys->keys, event->keyval);
}
gboolean PressedKeys_focus_in(ui::Widget widget, GdkEventFocus *event, PressedKeys *pressedKeys)
{
++pressedKeys->refcount;
return FALSE;
}
gboolean PressedKeys_focus_out(ui::Widget 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(ui::Window window)
{
unsigned int key_press_handler = window.connect("key_press_event", G_CALLBACK(PressedKeys_key_press),
&g_pressedKeys);
unsigned int key_release_handler = window.connect("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 = window.connect("focus_in_event", G_CALLBACK(PressedKeys_focus_in), &g_pressedKeys);
unsigned int focus_out_handler = window.connect("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(ui::Window 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<void()> &callback)
{
//globalOutputStream() << "special_accelerators_add: " << makeQuoted(accelerator) << "\n";
if (!accelerator_map_insert(g_special_accelerators, accelerator, callback)) {
globalErrorStream() << "special_accelerators_add: already exists: " << makeQuoted(accelerator) << "\n";
}
}
void special_accelerators_remove(Accelerator accelerator)
{
//globalOutputStream() << "special_accelerators_remove: " << makeQuoted(accelerator) << "\n";
if (!accelerator_map_erase(g_special_accelerators, accelerator)) {
globalErrorStream() << "special_accelerators_remove: not found: " << makeQuoted(accelerator) << "\n";
}
}
void keydown_accelerators_add(Accelerator accelerator, const Callback<void()> &callback)
{
//globalOutputStream() << "keydown_accelerators_add: " << makeQuoted(accelerator) << "\n";
if (!accelerator_map_insert(g_keydown_accelerators, accelerator, callback)) {
globalErrorStream() << "keydown_accelerators_add: already exists: " << makeQuoted(accelerator) << "\n";
}
}
void keydown_accelerators_remove(Accelerator accelerator)
{
//globalOutputStream() << "keydown_accelerators_remove: " << makeQuoted(accelerator) << "\n";
if (!accelerator_map_erase(g_keydown_accelerators, accelerator)) {
globalErrorStream() << "keydown_accelerators_remove: not found: " << makeQuoted(accelerator) << "\n";
}
}
void keyup_accelerators_add(Accelerator accelerator, const Callback<void()> &callback)
{
//globalOutputStream() << "keyup_accelerators_add: " << makeQuoted(accelerator) << "\n";
if (!accelerator_map_insert(g_keyup_accelerators, accelerator, callback)) {
globalErrorStream() << "keyup_accelerators_add: already exists: " << makeQuoted(accelerator) << "\n";
}
}
void keyup_accelerators_remove(Accelerator accelerator)
{
//globalOutputStream() << "keyup_accelerators_remove: " << makeQuoted(accelerator) << "\n";
if (!accelerator_map_erase(g_keyup_accelerators, accelerator)) {
globalErrorStream() << "keyup_accelerators_remove: not found: " << makeQuoted(accelerator) << "\n";
}
}
gboolean
accel_closure_callback(ui::AccelGroup group, ui::Widget widget, guint key, GdkModifierType modifiers, gpointer data)
{
(*reinterpret_cast<Callback<void()> *>( data ))();
return TRUE;
}
GClosure *accel_group_add_accelerator(ui::AccelGroup group, Accelerator accelerator, const Callback<void()> &callback)
{
if (accelerator.key != 0 && gtk_accelerator_valid(accelerator.key, accelerator.modifiers)) {
//globalOutputStream() << "global_accel_connect: " << makeQuoted(accelerator) << "\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(ui::AccelGroup group, Accelerator accelerator)
{
if (accelerator.key != 0 && gtk_accelerator_valid(accelerator.key, accelerator.modifiers)) {
//globalOutputStream() << "global_accel_disconnect: " << makeQuoted(accelerator) << "\n";
gtk_accel_group_disconnect_key(group, accelerator.key, accelerator.modifiers);
} else {
special_accelerators_remove(accelerator);
}
}
ui::AccelGroup global_accel{ui::New};
GClosure *global_accel_group_add_accelerator(Accelerator accelerator, const Callback<void()> &callback)
{
if (!global_accel_enabled()) {
// workaround: cannot add to GtkAccelGroup while it is disabled
//globalOutputStream() << "queued for add: " << accelerator << "\n";
globalQueuedAccelerators_add(accelerator, callback);
return 0;
}
return accel_group_add_accelerator(global_accel, accelerator, callback);
}
void global_accel_group_remove_accelerator(Accelerator accelerator)
{
if (!global_accel_enabled()) {
//globalOutputStream() << "queued for remove: " << accelerator << "\n";
globalQueuedAccelerators_remove(accelerator);
return;
}
accel_group_remove_accelerator(global_accel, accelerator);
}
/// \brief Propagates key events to the focus-widget, overriding global accelerators.
static gboolean override_global_accelerators(ui::Window window, GdkEventKey *event, gpointer data)
{
gboolean b = gtk_window_propagate_key_event(window, event);
return b;
}
void global_accel_connect_window(ui::Window window)
{
#if 1
unsigned int override_handler = window.connect("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 = window.connect("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 = window.connect( "key_press_event", G_CALLBACK( accelerator_key_event ), &g_keydown_accelerators );
unsigned int key_release_handler = window.connect( "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);
window.add_accel_group(global_accel);
}
void global_accel_disconnect_window(ui::Window 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 global_accel_group_connect(const Accelerator &accelerator, const Callback<void()> &callback)
{
if (accelerator.key != 0) {
global_accel_group_add_accelerator(accelerator, callback);
}
}
void global_accel_group_disconnect(const Accelerator &accelerator, const Callback<void()> &callback)
{
if (accelerator.key != 0) {
global_accel_group_remove_accelerator(accelerator);
}
}

View file

@ -1,164 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_GTKUTIL_ACCELERATOR_H )
#define INCLUDED_GTKUTIL_ACCELERATOR_H
#include <uilib/uilib.h>
#include <gdk/gdk.h>
#include "generic/callback.h"
#include "property.h"
// ignore numlock
#define ALLOWED_MODIFIERS ( ~( GDK_MOD2_MASK | GDK_LOCK_MASK | GDK_MOD3_MASK | GDK_MOD4_MASK | GDK_MOD5_MASK ) )
struct Accelerator {
Accelerator(guint _key)
: key(gdk_keyval_to_upper(_key)), modifiers((GdkModifierType) 0)
{
}
Accelerator(guint _key, GdkModifierType _modifiers)
: key(gdk_keyval_to_upper(_key)), modifiers((GdkModifierType) (_modifiers & ALLOWED_MODIFIERS))
{
}
Accelerator(const Accelerator &src)
: key(gdk_keyval_to_upper(src.key)), modifiers((GdkModifierType) (src.modifiers & ALLOWED_MODIFIERS))
{
}
bool operator<(const Accelerator &other) const
{
guint k1 = key;
guint k2 = other.key;
int mod1 = modifiers & ALLOWED_MODIFIERS;
int mod2 = other.modifiers & ALLOWED_MODIFIERS;
return k1 < k2 || (!(k2 < k1) && mod1 < mod2);
}
bool operator==(const Accelerator &other) const
{
guint k1 = key;
guint k2 = other.key;
int mod1 = modifiers & ALLOWED_MODIFIERS;
int mod2 = other.modifiers & ALLOWED_MODIFIERS;
return k1 == k2 && mod1 == mod2;
}
Accelerator &operator=(const Accelerator &other)
{
key = other.key;
modifiers = (GdkModifierType) (other.modifiers & ALLOWED_MODIFIERS);
return *this;
}
guint key;
GdkModifierType modifiers;
};
inline Accelerator accelerator_null()
{
return Accelerator(0, (GdkModifierType) 0);
}
const char *global_keys_find(unsigned int key);
unsigned int global_keys_find(const char *name);
class TextOutputStream;
void accelerator_write(const Accelerator &accelerator, TextOutputStream &ostream);
template<typename TextOutputStreamType>
TextOutputStreamType &ostream_write(TextOutputStreamType &ostream, const Accelerator &accelerator)
{
accelerator_write(accelerator, ostream);
return ostream;
}
void keydown_accelerators_add(Accelerator accelerator, const Callback<void()> &callback);
void keydown_accelerators_remove(Accelerator accelerator);
void keyup_accelerators_add(Accelerator accelerator, const Callback<void()> &callback);
void keyup_accelerators_remove(Accelerator accelerator);
void global_accel_connect_window(ui::Window window);
void global_accel_disconnect_window(ui::Window window);
void GlobalPressedKeys_releaseAll();
extern ui::AccelGroup global_accel;
GClosure *global_accel_group_find(Accelerator accelerator);
void global_accel_group_connect(const Accelerator &accelerator, const Callback<void()> &callback);
void global_accel_group_disconnect(const Accelerator &accelerator, const Callback<void()> &callback);
class Command {
public:
Callback<void()> m_callback;
const Accelerator &m_accelerator;
Command(const Callback<void()> &callback, const Accelerator &accelerator) : m_callback(callback),
m_accelerator(accelerator)
{
}
};
class Toggle {
public:
Command m_command;
Callback<void(const Callback<void(bool)> &)> m_exportCallback;
Toggle(const Callback<void()> &callback, const Accelerator &accelerator,
const Callback<void(const Callback<void(bool)> &)> &exportCallback) : m_command(callback, accelerator),
m_exportCallback(exportCallback)
{
}
};
class KeyEvent {
public:
const Accelerator &m_accelerator;
Callback<void()> m_keyDown;
Callback<void()> m_keyUp;
KeyEvent(const Accelerator &accelerator, const Callback<void()> &keyDown, const Callback<void()> &keyUp)
: m_accelerator(accelerator), m_keyDown(keyDown), m_keyUp(keyUp)
{
}
};
struct PressedButtons;
void PressedButtons_connect(PressedButtons &pressedButtons, ui::Widget widget);
extern PressedButtons g_pressedButtons;
#endif

View file

@ -1,160 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "button.h"
#include <gtk/gtk.h>
#include "stream/textstream.h"
#include "stream/stringstream.h"
#include "generic/callback.h"
#include "image.h"
#include "pointer.h"
void clicked_closure_callback(ui::Widget widget, gpointer data)
{
(*reinterpret_cast<Callback<void()> *>( data ))();
}
void button_connect_callback(ui::Button button, const Callback<void()> &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
}
void button_connect_callback(ui::ToolButton button, const Callback<void()> &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(ui::ToggleButton button, const Callback<void()> &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;
}
guint toggle_button_connect_callback(ui::ToggleToolButton button, const Callback<void()> &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(ui::Button button, const char *icon)
{
ui::Image image = ui::Image(new_local_image(icon));
image.show();
button.add(image);
}
void toggle_button_set_active_no_signal(ui::ToggleButton 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 toggle_button_set_active_no_signal(ui::ToggleToolButton button, gboolean active)
{
guint handler_id = gpointer_to_int(g_object_get_data(G_OBJECT(button), "handler"));
g_signal_handler_block(G_OBJECT(button), handler_id);
gtk_toggle_tool_button_set_active(button, active);
g_signal_handler_unblock(G_OBJECT(button), handler_id);
}
void radio_button_print_state(ui::RadioButton button)
{
globalOutputStream() << "toggle button: ";
for (GSList *radio = gtk_radio_button_get_group(button); radio != 0; radio = g_slist_next(radio)) {
globalOutputStream() << gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio->data));
}
globalOutputStream() << "\n";
}
ui::ToggleButton radio_button_get_nth(ui::RadioButton radio, int index)
{
GSList *group = gtk_radio_button_get_group(radio);
return ui::ToggleButton::from(g_slist_nth_data(group, g_slist_length(group) - index - 1));
}
void radio_button_set_active(ui::RadioButton 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(ui::RadioButton 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(ui::RadioButton radio)
{
//radio_button_print_state(radio);
GSList *group = gtk_radio_button_get_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

@ -1,52 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_GTKUTIL_BUTTON_H )
#define INCLUDED_GTKUTIL_BUTTON_H
#include <uilib/uilib.h>
#include "generic/callback.h"
typedef int gint;
typedef gint gboolean;
typedef unsigned int guint;
void button_connect_callback(ui::Button button, const Callback<void()> &callback);
void button_connect_callback(ui::ToolButton button, const Callback<void()> &callback);
guint toggle_button_connect_callback(ui::ToggleButton button, const Callback<void()> &callback);
guint toggle_button_connect_callback(ui::ToggleToolButton button, const Callback<void()> &callback);
void button_set_icon(ui::Button button, const char *icon);
void toggle_button_set_active_no_signal(ui::ToggleButton item, gboolean active);
void toggle_button_set_active_no_signal(ui::ToggleToolButton item, gboolean active);
void radio_button_set_active(ui::RadioButton radio, int index);
void radio_button_set_active_no_signal(ui::RadioButton radio, int index);
int radio_button_get_active(ui::RadioButton radio);
#endif

View file

@ -1,155 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "clipboard.h"
#include "globaldefs.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 GDEF_OS_WINDOWS
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();
}
}
#else
#include <gtk/gtk.h>
enum {
RADIANT_CLIPPINGS = 23,
};
static char RADIANT_CLIPPINGS_STR[] = "RADIANT_CLIPPINGS";
static const GtkTargetEntry clipboard_targets[] = {
{RADIANT_CLIPPINGS_STR, 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 (gtk_selection_data_get_length(data) < 0) {
globalErrorStream() << "Error retrieving selection\n";
} else if (strcmp(gdk_atom_name(gtk_selection_data_get_data_type(data)), clipboard_targets[0].target) == 0) {
BufferInputStream istream(reinterpret_cast<const char *>( gtk_selection_data_get_data(data)),
gtk_selection_data_get_length(data));
(*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);
}
#endif

View file

@ -1,37 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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

@ -1,77 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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<void()> *>( data );
}
inline GClosure *create_cclosure(GCallback func, const Callback<void()> &callback)
{
return g_cclosure_new(func, new Callback<void()>(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

@ -1,32 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_GTKUTIL_CONTAINER_H )
#define INCLUDED_GTKUTIL_CONTAINER_H
inline void container_remove_all(ui::Container container)
{
container.foreach([=](ui::Widget it) mutable {
container.remove(it);
});
}
#endif

View file

@ -1,131 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "cursor.h"
#include "stream/textstream.h"
#include <string.h>
#include <gdk/gdk.h>
#include <gtk/gtk.h>
GdkCursor *create_blank_cursor()
{
return gdk_cursor_new(GDK_BLANK_CURSOR);
}
void blank_cursor(ui::Widget widget)
{
GdkCursor *cursor = create_blank_cursor();
gdk_window_set_cursor(gtk_widget_get_window(widget), cursor);
gdk_cursor_unref(cursor);
}
void default_cursor(ui::Widget widget)
{
gdk_window_set_cursor(gtk_widget_get_window(widget), 0);
}
void Sys_GetCursorPos(ui::Window window, int *x, int *y)
{
gdk_display_get_pointer(gdk_display_get_default(), 0, x, y, 0);
}
void Sys_SetCursorPos(ui::Window window, int x, int y)
{
GdkScreen *screen;
gdk_display_get_pointer(gdk_display_get_default(), &screen, 0, 0, 0);
gdk_display_warp_pointer(gdk_display_get_default(), screen, x, y);
}
gboolean DeferredMotion::gtk_motion(ui::Widget widget, GdkEventMotion *event, DeferredMotion *self)
{
self->motion(event->x, event->y, event->state);
return FALSE;
}
gboolean FreezePointer::motion_delta(ui::Window widget, GdkEventMotion *event, FreezePointer *self)
{
int current_x, current_y;
Sys_GetCursorPos(widget, &current_x, &current_y);
int dx = current_x - self->last_x;
int dy = current_y - self->last_y;
int ddx = current_x - self->recorded_x;
int ddy = current_y - self->recorded_y;
self->last_x = current_x;
self->last_y = current_y;
if (dx != 0 || dy != 0) {
//globalOutputStream() << "motion x: " << dx << ", y: " << dy << "\n";
if (ddx < -32 || ddx > 32 || ddy < -32 || ddy > 32) {
Sys_SetCursorPos(widget, self->recorded_x, self->recorded_y);
self->last_x = self->recorded_x;
self->last_y = self->recorded_y;
}
self->m_function(dx, dy, event->state, self->m_data);
}
return FALSE;
}
void FreezePointer::freeze_pointer(ui::Window window, FreezePointer::MotionDeltaFunction function, void *data)
{
ASSERT_MESSAGE(m_function == 0, "can't freeze pointer");
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 );
GdkCursor *cursor = create_blank_cursor();
//GdkGrabStatus status =
gdk_pointer_grab(gtk_widget_get_window(window), TRUE, mask, 0, cursor, GDK_CURRENT_TIME);
gdk_cursor_unref(cursor);
Sys_GetCursorPos(window, &recorded_x, &recorded_y);
Sys_SetCursorPos(window, recorded_x, recorded_y);
last_x = recorded_x;
last_y = recorded_y;
m_function = function;
m_data = data;
handle_motion = window.connect("motion_notify_event", G_CALLBACK(motion_delta), this);
}
void FreezePointer::unfreeze_pointer(ui::Window window)
{
g_signal_handler_disconnect(G_OBJECT(window), handle_motion);
m_function = 0;
m_data = 0;
Sys_SetCursorPos(window, recorded_x, recorded_y);
gdk_pointer_ungrab(GDK_CURRENT_TIME);
}

View file

@ -1,146 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_GTKUTIL_CURSOR_H )
#define INCLUDED_GTKUTIL_CURSOR_H
#include <uilib/uilib.h>
#include "debugging/debugging.h"
typedef struct _GdkCursor GdkCursor;
typedef struct _GdkEventMotion GdkEventMotion;
GdkCursor *create_blank_cursor();
void blank_cursor(ui::Widget widget);
void default_cursor(ui::Widget widget);
void Sys_GetCursorPos(ui::Window window, int *x, int *y);
void Sys_SetCursorPos(ui::Window window, 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(ui::Widget widget, GdkEventMotion *event, DeferredMotion *self);
};
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, last_x, last_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(ui::Window widget, GdkEventMotion *event, FreezePointer *self);
void freeze_pointer(ui::Window window, MotionDeltaFunction function, void *data);
void unfreeze_pointer(ui::Window window);
};
#endif

View file

@ -1,293 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dialog.h"
#include <gtk/gtk.h>
#include "button.h"
#include "window.h"
ui::VBox create_dialog_vbox(int spacing, int border)
{
auto vbox = ui::VBox(FALSE, spacing);
vbox.show();
gtk_container_set_border_width(GTK_CONTAINER(vbox), border);
return vbox;
}
ui::HBox create_dialog_hbox(int spacing, int border)
{
auto hbox = ui::HBox(FALSE, spacing);
hbox.show();
gtk_container_set_border_width(GTK_CONTAINER(hbox), border);
return hbox;
}
ui::Frame create_dialog_frame(const char *label, ui::Shadow shadow)
{
auto frame = ui::Frame(label);
frame.show();
gtk_frame_set_shadow_type(frame, (GtkShadowType) shadow);
return frame;
}
ui::Table
create_dialog_table(unsigned int rows, unsigned int columns, unsigned int row_spacing, unsigned int col_spacing,
int border)
{
auto table = ui::Table(rows, columns, FALSE);
table.show();
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;
}
ui::Button create_dialog_button(const char *label, GCallback func, gpointer data)
{
auto button = ui::Button(label);
button.dimensions(64, -1);
button.show();
button.connect("clicked", func, data);
return button;
}
ui::Window
create_dialog_window(ui::Window parent, const char *title, GCallback func, gpointer data, int default_w, int default_h)
{
ui::Window 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);
window.connect("delete_event", func, data);
return window;
}
gboolean modal_dialog_button_clicked(ui::Widget widget, ModalDialogButton *button)
{
button->m_dialog.loop = false;
button->m_dialog.ret = button->m_value;
return TRUE;
}
gboolean modal_dialog_delete(ui::Widget widget, GdkEvent *event, ModalDialog *dialog)
{
dialog->loop = 0;
dialog->ret = eIDCANCEL;
return TRUE;
}
EMessageBoxReturn modal_dialog_show(ui::Window window, ModalDialog &dialog)
{
gtk_grab_add(window);
window.show();
dialog.loop = true;
while (dialog.loop) {
gtk_main_iteration();
}
window.hide();
gtk_grab_remove(window);
return dialog.ret;
}
ui::Button create_modal_dialog_button(const char *label, ModalDialogButton &button)
{
return create_dialog_button(label, G_CALLBACK(modal_dialog_button_clicked), &button);
}
ui::Window
create_modal_dialog_window(ui::Window 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);
}
ui::Window
create_fixedsize_modal_dialog_window(ui::Window parent, const char *title, ModalDialog &dialog, int width, int height)
{
auto 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);
//window.dimensions(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, window, &geometry, (GdkWindowHints)(GDK_HINT_POS|GDK_HINT_MIN_SIZE|GDK_HINT_BASE_SIZE));
return window;
}
gboolean dialog_button_ok(ui::Widget widget, ModalDialog *data)
{
data->loop = false;
data->ret = eIDOK;
return TRUE;
}
gboolean dialog_button_cancel(ui::Widget widget, ModalDialog *data)
{
data->loop = false;
data->ret = eIDCANCEL;
return TRUE;
}
gboolean dialog_button_yes(ui::Widget widget, ModalDialog *data)
{
data->loop = false;
data->ret = eIDYES;
return TRUE;
}
gboolean dialog_button_no(ui::Widget widget, ModalDialog *data)
{
data->loop = false;
data->ret = eIDNO;
return TRUE;
}
gboolean dialog_delete_callback(ui::Widget widget, GdkEventAny *event, ModalDialog *data)
{
widget.hide();
data->loop = false;
return TRUE;
}
ui::Window create_simple_modal_dialog_window(const char *title, ModalDialog &dialog, ui::Widget contents)
{
ui::Window window = create_fixedsize_modal_dialog_window(ui::Window{ui::null}, title, dialog);
auto vbox1 = create_dialog_vbox(8, 4);
window.add(vbox1);
vbox1.add(contents);
ui::Alignment alignment = ui::Alignment(0.5, 0.0, 0.0, 0.0);
alignment.show();
vbox1.pack_start(alignment, FALSE, FALSE, 0);
auto button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &dialog);
alignment.add(button);
return window;
}
RadioHBox RadioHBox_new(StringArrayRange names)
{
auto hbox = ui::HBox(TRUE, 4);
hbox.show();
GSList *group = 0;
auto radio = ui::RadioButton(ui::null);
for (StringArrayRange::Iterator i = names.first; i != names.last; ++i) {
radio = ui::RadioButton::from(gtk_radio_button_new_with_label(group, *i));
radio.show();
hbox.pack_start(radio, FALSE, FALSE, 0);
group = gtk_radio_button_get_group(radio);
}
return RadioHBox(hbox, radio);
}
PathEntry PathEntry_new()
{
auto frame = ui::Frame();
frame.show();
gtk_frame_set_shadow_type(frame, GTK_SHADOW_IN);
// path entry
auto hbox = ui::HBox(FALSE, 0);
hbox.show();
auto entry = ui::Entry(ui::New);
gtk_entry_set_has_frame(entry, FALSE);
entry.show();
hbox.pack_start(entry, TRUE, TRUE, 0);
// browse button
auto button = ui::Button(ui::New);
button_set_icon(button, "ellipsis.bmp");
button.show();
hbox.pack_end(button, FALSE, FALSE, 0);
frame.add(hbox);
return PathEntry(frame, entry, button);
}
void PathEntry_setPath(PathEntry &self, const char *path)
{
gtk_entry_set_text(self.m_entry, path);
}
typedef ReferenceCaller<PathEntry, void (const char *), PathEntry_setPath> PathEntrySetPathCaller;
void BrowsedPathEntry_clicked(ui::Widget widget, BrowsedPathEntry *self)
{
self->m_browse(PathEntrySetPathCaller(self->m_entry));
}
BrowsedPathEntry::BrowsedPathEntry(const BrowseCallback &browse) :
m_entry(PathEntry_new()),
m_browse(browse)
{
m_entry.m_button.connect("clicked", G_CALLBACK(BrowsedPathEntry_clicked), this);
}
ui::Label DialogLabel_new(const char *name)
{
auto label = ui::Label(name);
label.show();
gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
gtk_label_set_justify(label, GTK_JUSTIFY_LEFT);
return label;
}
ui::Table DialogRow_new(const char *name, ui::Widget widget)
{
auto table = ui::Table(1, 3, TRUE);
table.show();
gtk_table_set_col_spacings(table, 4);
gtk_table_set_row_spacings(table, 0);
table.attach(DialogLabel_new(name), {0, 1, 0, 1}, {GTK_EXPAND | GTK_FILL, 0});
table.attach(widget, {1, 3, 0, 1}, {GTK_EXPAND | GTK_FILL, 0});
return table;
}
void DialogVBox_packRow(ui::Box vbox, ui::Widget row)
{
vbox.pack_start(row, FALSE, FALSE, 0);
}

View file

@ -1,148 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_GTKUTIL_DIALOG_H )
#define INCLUDED_GTKUTIL_DIALOG_H
#include "generic/callback.h"
#include "generic/arrayrange.h"
#include "qerplugin.h"
typedef int gint;
typedef gint gboolean;
typedef struct _GdkEventAny GdkEventAny;
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;
ui::Window create_fixedsize_modal_window(ui::Window parent, const char *title, int width, int height);
ui::Window create_dialog_window(ui::Window parent, const char *title, GCallback func, gpointer data, int default_w = -1,
int default_h = -1);
ui::Table
create_dialog_table(unsigned int rows, unsigned int columns, unsigned int row_spacing, unsigned int col_spacing,
int border = 0);
ui::Button create_dialog_button(const char *label, GCallback func, gpointer data);
ui::VBox create_dialog_vbox(int spacing, int border = 0);
ui::HBox create_dialog_hbox(int spacing, int border = 0);
ui::Frame create_dialog_frame(const char *label, ui::Shadow shadow = ui::Shadow::ETCHED_IN);
ui::Button create_modal_dialog_button(const char *label, ModalDialogButton &button);
ui::Window create_modal_dialog_window(ui::Window parent, const char *title, ModalDialog &dialog, int default_w = -1,
int default_h = -1);
ui::Window
create_fixedsize_modal_dialog_window(ui::Window parent, const char *title, ModalDialog &dialog, int width = -1,
int height = -1);
EMessageBoxReturn modal_dialog_show(ui::Window window, ModalDialog &dialog);
gboolean dialog_button_ok(ui::Widget widget, ModalDialog *data);
gboolean dialog_button_cancel(ui::Widget widget, ModalDialog *data);
gboolean dialog_button_yes(ui::Widget widget, ModalDialog *data);
gboolean dialog_button_no(ui::Widget widget, ModalDialog *data);
gboolean dialog_delete_callback(ui::Widget widget, GdkEventAny *event, ModalDialog *data);
ui::Window create_simple_modal_dialog_window(const char *title, ModalDialog &dialog, ui::Widget contents);
class RadioHBox {
public:
ui::HBox m_hbox;
ui::RadioButton m_radio;
RadioHBox(ui::HBox hbox, ui::RadioButton radio) :
m_hbox(hbox),
m_radio(radio)
{
}
};
RadioHBox RadioHBox_new(StringArrayRange names);
class PathEntry {
public:
ui::Frame m_frame;
ui::Entry m_entry;
ui::Button m_button;
PathEntry(ui::Frame frame, ui::Entry entry, ui::Button button) :
m_frame(frame),
m_entry(entry),
m_button(button)
{
}
};
PathEntry PathEntry_new();
class BrowsedPathEntry {
public:
typedef Callback<void (const char *)> SetPathCallback;
typedef Callback<void (const SetPathCallback &)> BrowseCallback;
PathEntry m_entry;
BrowseCallback m_browse;
BrowsedPathEntry(const BrowseCallback &browse);
};
ui::Label DialogLabel_new(const char *name);
ui::Table DialogRow_new(const char *name, ui::Widget widget);
void DialogVBox_packRow(ui::Box vbox, ui::Widget row);
#endif

View file

@ -1,37 +0,0 @@
#include "entry.h"
#include <gtk/gtk.h>
void entry_set_string(ui::Entry entry, const char *string)
{
gtk_entry_set_text(entry, string);
}
void entry_set_int(ui::Entry entry, int i)
{
char buf[32];
sprintf(buf, "%d", i);
entry_set_string(entry, buf);
}
void entry_set_float(ui::Entry entry, float f)
{
char buf[32];
sprintf(buf, "%g", f);
entry_set_string(entry, buf);
}
const char *entry_get_string(ui::Entry entry)
{
return gtk_entry_get_text(entry);
}
int entry_get_int(ui::Entry entry)
{
return atoi(entry_get_string(entry));
}
double entry_get_float(ui::Entry entry)
{
return atof(entry_get_string(entry));
}

View file

@ -1,39 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <uilib/uilib.h>
#if !defined( INCLUDED_GTKUTIL_ENTRY_H )
#define INCLUDED_GTKUTIL_ENTRY_H
void entry_set_string(ui::Entry entry, const char *string);
void entry_set_int(ui::Entry entry, int i);
void entry_set_float(ui::Entry entry, float f);
const char *entry_get_string(ui::Entry entry);
int entry_get_int(ui::Entry entry);
double entry_get_float(ui::Entry entry);
#endif

View file

@ -1,287 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "filechooser.h"
#include "ifiletypes.h"
#include <list>
#include <vector>
#include <gtk/gtk.h>
#include <uilib/uilib.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));
}
};
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(ui::Window parent, bool open, const char *title, const char *path, const char *pattern, bool want_load,
bool want_import, bool want_save)
{
filetype_t type;
if (pattern == 0) {
pattern = "*";
}
FileTypeList typelist;
GlobalFiletypes().getTypeList(pattern, &typelist, want_load, want_import, want_save);
GTKMasks masks(typelist);
if (title == 0) {
title = open ? "Open File" : "Save File";
}
ui::Dialog dialog{ui::null};
if (open) {
dialog = ui::Dialog::from(gtk_file_chooser_dialog_new(title,
parent,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL));
} else {
dialog = ui::Dialog::from(gtk_file_chooser_dialog_new(title,
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(dialog, TRUE);
gtk_window_set_position(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));
if (filter !=
0) { // no filter set? some file-chooser implementations may allow the user to set no filter, which we treat as 'all files'
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';
}
ui::Widget(dialog).destroy();
// don't return an empty filename
if (g_file_dialog_file[0] == '\0') {
return NULL;
}
return g_file_dialog_file;
}
char *dir_dialog(ui::Window parent, const char *title, const char *path)
{
auto dialog = ui::Dialog::from(gtk_file_chooser_dialog_new(title,
parent,
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL));
gtk_window_set_modal(dialog, TRUE);
gtk_window_set_position(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));
}
dialog.destroy();
return filename;
}
const char *
file_dialog(ui::Window parent, bool open, const char *title, const char *path, const char *pattern, bool want_load,
bool want_import, bool want_save)
{
for (;;) {
const char *file = file_dialog_show(parent, open, title, path, pattern, want_load, want_import, want_save);
if (open
|| !file
|| !file_exists(file)
|| ui::alert(parent, "The file specified already exists.\nDo you want to replace it?", title,
ui::alert_type::NOYES, ui::alert_icon::Question) == ui::alert_response::YES) {
return file;
}
}
}

View file

@ -1,40 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <uilib/uilib.h>
#if !defined( INCLUDED_GTKUTIL_FILECHOOSER_H )
#define INCLUDED_GTKUTIL_FILECHOOSER_H
/// \file
/// GTK+ file-chooser dialogs.
const char *file_dialog(ui::Window parent, bool open, const char *title, const char *path = 0, const char *pattern = 0,
bool want_load = false, bool want_import = false, bool want_save = false);
/// \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(ui::Window parent, const char *title = "Choose Directory", const char *path = "");
#endif

View file

@ -1,35 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "frame.h"
#include <gtk/gtk.h>
#include <uilib/uilib.h>
ui::Frame create_framed_widget(ui::Widget widget)
{
auto frame = ui::Frame();
frame.show();
gtk_frame_set_shadow_type(frame, GTK_SHADOW_IN);
frame.add(widget);
widget.show();
return frame;
}

View file

@ -1,29 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <uilib/uilib.h>
#if !defined( INCLUDED_GTKUTIL_FRAME_H )
#define INCLUDED_GTKUTIL_FRAME_H
ui::Frame create_framed_widget(ui::Widget widget);
#endif

View file

@ -1,362 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "glfont.h"
#include "globaldefs.h"
#include "igl.h"
// generic string printing with call lists
class GLFontCallList : public GLFont {
GLuint m_displayList;
int m_pixelHeight;
int m_pixelAscent;
int m_pixelDescent;
public:
GLFontCallList(GLuint displayList, int asc, int desc, int pixelHeight) : m_displayList(displayList),
m_pixelHeight(pixelHeight),
m_pixelAscent(asc), m_pixelDescent(desc)
{
}
virtual ~GLFontCallList()
{
glDeleteLists(m_displayList, 256);
}
void printString(const char *s)
{
GlobalOpenGL().m_glListBase(m_displayList);
GlobalOpenGL().m_glCallLists(GLsizei(strlen(s)), GL_UNSIGNED_BYTE, reinterpret_cast<const GLubyte *>( s ));
}
virtual int getPixelAscent() const
{
return m_pixelAscent;
}
virtual int getPixelDescent() const
{
return m_pixelDescent;
}
virtual int getPixelHeight() const
{
return m_pixelHeight;
}
};
#if GDEF_OS_WINDOWS
#include <windows.h>
#endif
#include "debugging/debugging.h"
// LordHavoc: this is code for direct Xlib bitmap character fetching, as an
// alternative to requiring gtkglarea, it was created due to a lack of this
// package on SuSE 9.x but this package is now commonly shipping in Linux
// distributions so this code may be unnecessary, feel free however to enable
// it when building packages for distros that do not ship with that package,
// or if you just prefer less dependencies...
#if 0
#include <X11/Xlib.h>
#include <gdk/gdkx.h>
#include <GL/glx.h>
GLFont *glfont_create( const char* font_string ){
GLuint font_list_base;
XFontStruct *fontInfo;
Display *dpy = GDK_DISPLAY();
unsigned int i, first, last, firstrow, lastrow;
int maxchars;
int firstbitmap;
fontInfo = XLoadQueryFont( dpy, "-*-fixed-*-*-*-*-8-*-*-*-*-*-*-*" );
if ( fontInfo == NULL ) {
// try to load other fonts
fontInfo = XLoadQueryFont( dpy, "-*-fixed-*-*-*-*-*-*-*-*-*-*-*-*" );
// any font will do !
if ( fontInfo == NULL ) {
fontInfo = XLoadQueryFont( dpy, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" );
}
if ( fontInfo == NULL ) {
ERROR_MESSAGE( "couldn't create font" );
}
}
first = (int)fontInfo->min_char_or_byte2;
last = (int)fontInfo->max_char_or_byte2;
firstrow = (int)fontInfo->min_byte1;
lastrow = (int)fontInfo->max_byte1;
/*
* How many chars in the charset
*/
maxchars = 256 * lastrow + last;
font_list_base = glGenLists( maxchars + 1 );
if ( font_list_base == 0 ) {
ERROR_MESSAGE( "couldn't create font" );
}
/*
* Get offset to first char in the charset
*/
firstbitmap = 256 * firstrow + first;
/*
* for each row of chars, call glXUseXFont to build the bitmaps.
*/
for ( i = firstrow; i <= lastrow; i++ )
{
glXUseXFont( fontInfo->fid, firstbitmap, last - first + 1, font_list_base + firstbitmap );
firstbitmap += 256;
}
/* *height = fontInfo->ascent + fontInfo->descent;
* width = fontInfo->max_bounds.width; */
return new GLFontCallList( font_list_base, fontInfo->ascent, fontInfo->descent, fontInfo->ascent + fontInfo->descent );
}
#elif 0
#include <gtk/gtkglwidget.h>
GLFont *glfont_create( const char* font_string ){
GLuint font_list_base = glGenLists( 256 );
gint font_height = 0, font_ascent = 0, font_descent = 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 ) {
pango_font_description_free( font_desc );
font_desc = pango_font_description_from_string( "fixed 8" );
font = gdk_gl_font_use_pango_font( font_desc, 0, 256, font_list_base );
}
if ( font == 0 ) {
pango_font_description_free( font_desc );
font_desc = pango_font_description_from_string( "courier new 8" );
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_ascent = pango_font_metrics_get_ascent( font_metrics );
font_descent = pango_font_metrics_get_descent( font_metrics );
font_height = font_ascent + font_descent;
font_ascent = PANGO_PIXELS( font_ascent );
font_descent = PANGO_PIXELS( font_descent );
font_height = PANGO_PIXELS( font_height );
pango_font_metrics_unref( font_metrics );
}
pango_font_description_free( font_desc );
// fix for pango/gtkglext metrix bug
if ( font_height > 256 ) {
font_height = 16;
}
return new GLFontCallList( font_list_base, font_ascent, font_descent, font_height );
}
#else
// new font code ripped from ZeroRadiant
#include <pango/pangoft2.h>
#include <pango/pango-features.h>
#include <pango/pango-utils.h>
class GLFontInternal : public GLFont {
const char *font_string;
int font_height;
int font_ascent;
int font_descent;
int y_offset_bitmap_render_pango_units;
PangoContext *ft2_context;
PangoFontMap *fontmap;
public:
GLFontInternal(const char *_font_string) : font_string(_font_string)
{
PangoFontDescription *font_desc;
PangoLayout *layout;
PangoRectangle log_rect;
int font_ascent_pango_units;
int font_descent_pango_units;
#if !PANGO_VERSION_CHECK(1, 22, 0)
ft2_context = pango_ft2_get_context( 72, 72 );
#else
fontmap = pango_ft2_font_map_new();
pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(fontmap), 72, 72);
ft2_context = pango_font_map_create_context(fontmap);
#endif
font_desc = pango_font_description_from_string( "Liberation Mono 12" );
//pango_font_description_set_size(font_desc, 10 * PANGO_SCALE);
pango_context_set_font_description(ft2_context, font_desc);
pango_font_description_free(font_desc);
// TODO fallback to fixed 8, courier new 8
layout = pango_layout_new(ft2_context);
#ifdef FONT_SIZE_WORKAROUND
pango_layout_set_width( layout, -1 ); // -1 no wrapping. All text on one line.
pango_layout_set_text( layout, "The quick brown fox jumped over the lazy sleeping dog's back then sat on a tack.", -1 ); // -1 null-terminated string.
#endif
#if !PANGO_VERSION_CHECK(1, 22, 0)
PangoLayoutIter *iter;
iter = pango_layout_get_iter( layout );
font_ascent_pango_units = pango_layout_iter_get_baseline( iter );
pango_layout_iter_free( iter );
#else
font_ascent_pango_units = pango_layout_get_baseline(layout);
#endif
pango_layout_get_extents(layout, NULL, &log_rect);
g_object_unref(G_OBJECT(layout));
font_descent_pango_units = log_rect.height - font_ascent_pango_units;
font_ascent = PANGO_PIXELS_CEIL(font_ascent_pango_units);
font_descent = PANGO_PIXELS_CEIL(font_descent_pango_units);
font_height = font_ascent + font_descent;
y_offset_bitmap_render_pango_units = (font_ascent * PANGO_SCALE) - font_ascent_pango_units;
}
virtual ~GLFontInternal()
{
g_object_unref(G_OBJECT(ft2_context));
g_object_unref(G_OBJECT(fontmap));
}
// Renders the input text at the current location with the current color.
// The X position of the current location is used to place the left edge of the text image,
// where the text image bounds are defined as the logical extents of the line of text.
// The Y position of the current location is used to place the bottom of the text image.
// You should offset the Y position by the amount returned by gtk_glwidget_font_descent()
// if you want to place the baseline of the text image at the current Y position.
// Note: A problem with this function is that if the lower left corner of the text falls
// just a hair outside of the viewport (meaning the current raster position is invalid),
// then no text will be rendered. The solution to this is a very hacky one. You can search
// Google for "glDrawPixels clipping".
virtual void printString(const char *s)
{
// The idea for this code initially came from the font-pangoft2.c example that comes with GtkGLExt.
PangoLayout *layout;
PangoRectangle log_rect;
FT_Bitmap bitmap;
unsigned char *begin_bitmap_buffer;
GLfloat color[4];
GLint previous_unpack_alignment;
GLboolean previous_blend_enabled;
GLint previous_blend_func_src;
GLint previous_blend_func_dst;
GLfloat previous_red_bias;
GLfloat previous_green_bias;
GLfloat previous_blue_bias;
GLfloat previous_alpha_scale;
layout = pango_layout_new(ft2_context);
pango_layout_set_width(layout, -1); // -1 no wrapping. All text on one line.
pango_layout_set_text(layout, s, -1); // -1 null-terminated string.
pango_layout_get_extents(layout, NULL, &log_rect);
if (log_rect.width > 0 && log_rect.height > 0) {
bitmap.rows = font_ascent + font_descent;
bitmap.width = PANGO_PIXELS_CEIL(log_rect.width);
bitmap.pitch = -bitmap.width; // Rendering it "upside down" for OpenGL.
begin_bitmap_buffer = (unsigned char *) g_malloc(bitmap.rows * bitmap.width);
memset(begin_bitmap_buffer, 0, bitmap.rows * bitmap.width);
bitmap.buffer = begin_bitmap_buffer + (bitmap.rows - 1) * bitmap.width; // See pitch above.
bitmap.num_grays = 0xff;
bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
pango_ft2_render_layout_subpixel(&bitmap, layout, -log_rect.x,
y_offset_bitmap_render_pango_units);
GlobalOpenGL().m_glGetFloatv(GL_CURRENT_COLOR, color);
// Save state. I didn't see any OpenGL push/pop operations for these.
// Question: Is saving/restoring this state necessary? Being safe.
GlobalOpenGL().m_glGetIntegerv(GL_UNPACK_ALIGNMENT, &previous_unpack_alignment);
previous_blend_enabled = GlobalOpenGL().m_glIsEnabled(GL_BLEND);
GlobalOpenGL().m_glGetIntegerv(GL_BLEND_SRC, &previous_blend_func_src);
GlobalOpenGL().m_glGetIntegerv(GL_BLEND_DST, &previous_blend_func_dst);
GlobalOpenGL().m_glGetFloatv(GL_RED_BIAS, &previous_red_bias);
GlobalOpenGL().m_glGetFloatv(GL_GREEN_BIAS, &previous_green_bias);
GlobalOpenGL().m_glGetFloatv(GL_BLUE_BIAS, &previous_blue_bias);
GlobalOpenGL().m_glGetFloatv(GL_ALPHA_SCALE, &previous_alpha_scale);
GlobalOpenGL().m_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GlobalOpenGL().m_glEnable(GL_BLEND);
GlobalOpenGL().m_glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GlobalOpenGL().m_glPixelTransferf(GL_RED_BIAS, color[0]);
GlobalOpenGL().m_glPixelTransferf(GL_GREEN_BIAS, color[1]);
GlobalOpenGL().m_glPixelTransferf(GL_BLUE_BIAS, color[2]);
GlobalOpenGL().m_glPixelTransferf(GL_ALPHA_SCALE, color[3]);
GlobalOpenGL().m_glDrawPixels(bitmap.width, bitmap.rows,
GL_ALPHA, GL_UNSIGNED_BYTE, begin_bitmap_buffer);
g_free(begin_bitmap_buffer);
// Restore state in reverse order of how we set it.
GlobalOpenGL().m_glPixelTransferf(GL_ALPHA_SCALE, previous_alpha_scale);
GlobalOpenGL().m_glPixelTransferf(GL_BLUE_BIAS, previous_blue_bias);
GlobalOpenGL().m_glPixelTransferf(GL_GREEN_BIAS, previous_green_bias);
GlobalOpenGL().m_glPixelTransferf(GL_RED_BIAS, previous_red_bias);
GlobalOpenGL().m_glBlendFunc(previous_blend_func_src, previous_blend_func_dst);
if (!previous_blend_enabled) {
GlobalOpenGL().m_glDisable(GL_BLEND);
}
GlobalOpenGL().m_glPixelStorei(GL_UNPACK_ALIGNMENT, previous_unpack_alignment);
}
g_object_unref(G_OBJECT(layout));
}
virtual int getPixelAscent() const
{
return font_ascent;
}
virtual int getPixelDescent() const
{
return font_descent;
}
virtual int getPixelHeight() const
{
return font_height;
}
};
GLFont *glfont_create(const char *font_string)
{
return new GLFontInternal(font_string);
}
#endif

View file

@ -1,45 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined( INCLUDED_GTKUTIL_GLFONT_H )
#define INCLUDED_GTKUTIL_GLFONT_H
typedef unsigned int GLuint;
class GLFont {
public:
virtual int getPixelHeight() const = 0;
virtual int getPixelAscent() const = 0;
virtual int getPixelDescent() const = 0;
virtual void printString(const char *s) = 0;
virtual ~GLFont()
{
}
};
GLFont *glfont_create(const char *font_string);
// release with delete
#endif

View file

@ -1,304 +0,0 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
// OpenGL widget based on GtkGLExt
#include "glwidget.h"
#include "igl.h"
void (*GLWidget_sharedContextCreated)() = 0;
void (*GLWidget_sharedContextDestroyed)() = 0;
unsigned int g_context_count = 0;
ui::GLArea g_shared{ui::null};
void _glwidget_context_created(ui::GLArea self, void *data)
{
if (++g_context_count == 1) {
g_shared = self;
g_object_ref(g_shared._handle);
glwidget_make_current(g_shared);
GlobalOpenGL().contextValid = true;
GLWidget_sharedContextCreated();
}
}
void _glwidget_context_destroyed(ui::GLArea self, void *data)
{
if (--g_context_count == 0) {
GlobalOpenGL().contextValid = false;
GLWidget_sharedContextDestroyed();
g_shared.unref();
g_shared = ui::GLArea(ui::null);
}
}
void glwidget_destroy_context(ui::GLArea self)
{
}
void glwidget_create_context(ui::GLArea self)
{
}
#if GTK_TARGET == 3
#include <gtk/gtk.h>
GdkGLContext *glwidget_context_created(ui::GLArea self)
{
_glwidget_context_created(self, nullptr);
return gtk_gl_area_get_context(self);
}
ui::GLArea glwidget_new(bool zbuffer)
{
auto self = ui::GLArea(GTK_GL_AREA(gtk_gl_area_new()));
gtk_gl_area_set_has_depth_buffer(self, zbuffer);
gtk_gl_area_set_auto_render(self, false);
self.connect("realize", G_CALLBACK(glwidget_context_created), nullptr);
return self;
}
bool glwidget_make_current(ui::GLArea self)
{
// if (!g_context_count) {
// glwidget_context_created(self);
// }
gtk_gl_area_make_current(self);
auto valid = GlobalOpenGL().contextValid;
return true;
}
void glwidget_swap_buffers(ui::GLArea self)
{
gtk_gl_area_queue_render(self);
}
#endif
#if GTK_TARGET == 2
#include <gtk/gtk.h>
#include <gtk/gtkglwidget.h>
#include "pointer.h"
struct config_t {
const char *name;
int *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()
{
for (configs_iterator i = configs, end = configs + 2; i != end; ++i) {
if (auto glconfig = gdk_gl_config_new(i->attribs)) {
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()
{
for (configs_iterator i = configs_with_depth, end = configs_with_depth + 6; i != end; ++i) {
if (auto glconfig = gdk_gl_config_new(i->attribs)) {
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));
}
int glwidget_context_created(ui::GLArea self, void *data)
{
_glwidget_context_created(self, data);
return false;
}
int glwidget_context_destroyed(ui::GLArea self, void *data)
{
_glwidget_context_destroyed(self, data);
return false;
}
bool glwidget_enable_gl(ui::GLArea self, ui::Widget root, gpointer data)
{
if (!root && !gtk_widget_is_gl_capable(self)) {
const auto zbuffer = g_object_get_data(G_OBJECT(self), "zbuffer");
GdkGLConfig *glconfig = zbuffer ? glconfig_new_with_depth() : glconfig_new();
ASSERT_MESSAGE(glconfig, "failed to create OpenGL config");
const auto share_list = g_shared ? gtk_widget_get_gl_context(g_shared) : nullptr;
gtk_widget_set_gl_capability(self, glconfig, share_list, true, GDK_GL_RGBA_TYPE);
gtk_widget_realize(self);
if (!g_shared) {
g_shared = self;
}
// free glconfig?
}
return false;
}
ui::GLArea glwidget_new(bool zbuffer)
{
auto self = ui::GLArea::from(gtk_drawing_area_new());
g_object_set_data(G_OBJECT(self), "zbuffer", gint_to_pointer(zbuffer));
self.connect("hierarchy-changed", G_CALLBACK(glwidget_enable_gl), 0);
self.connect("realize", G_CALLBACK(glwidget_context_created), 0);
self.connect("unrealize", G_CALLBACK(glwidget_context_destroyed), 0);
return self;
}
void glwidget_swap_buffers(ui::GLArea self)
{
GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(self);
gdk_gl_drawable_swap_buffers(gldrawable);
}
bool glwidget_make_current(ui::GLArea self)
{
GdkGLContext *glcontext = gtk_widget_get_gl_context(self);
GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(self);
return gdk_gl_drawable_gl_begin(gldrawable, glcontext);
}
#endif

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