Separate from WorldSpawn
This commit is contained in:
parent
3026ccf374
commit
2ae68a5c85
694 changed files with 167 additions and 162291 deletions
6
Makefile
6
Makefile
|
@ -1,13 +1,7 @@
|
||||||
all:
|
all:
|
||||||
mkdir -p ./build
|
|
||||||
cd libs && $(MAKE)
|
cd libs && $(MAKE)
|
||||||
cd src && $(MAKE)
|
cd src && $(MAKE)
|
||||||
cd plugins && $(MAKE)
|
|
||||||
cd tools && $(MAKE)
|
|
||||||
cd resources && $(MAKE)
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
cd libs && $(MAKE) clean
|
cd libs && $(MAKE) clean
|
||||||
cd src && $(MAKE) clean
|
cd src && $(MAKE) clean
|
||||||
cd plugins && $(MAKE) clean
|
|
||||||
cd tools && $(MAKE) clean
|
|
||||||
|
|
93
README.md
93
README.md
|
@ -1,83 +1,64 @@
|
||||||
# ![WorldSpawn Logo](icon.png) WorldSpawn
|
# vmap
|
||||||
The worlds most opinionated fork of Radiant.
|
|
||||||
|
|
||||||
The editor we use at Vera Visions to create BSP levels.
|
A fork of q3map2, now available as a stand-alone compiler targetting [FTEQW](https://www.fteqw.org/)
|
||||||
It was forked from NetRadiant in June of 2018 and was a result of necessity.
|
|
||||||
|
|
||||||
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.
|
## Compiler Changes
|
||||||
You will not be able to make levels compatible with other games and engines.
|
- Improved High-Dynamic-Range lightmaps
|
||||||
|
- Support for our patchDef2WS and patchDef3WS curved surfaces in the BSP compiler, allowing for 4-way texture blended patches.
|
||||||
There's plenty of other editors for the first-party id Tech games.
|
- Reads individual material scripts (.mat) instead of large .shader files
|
||||||
**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.**
|
- 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
|
||||||
**Please respect this notice, thank you.**
|
- Handles Half-Life styled point lights, including zhlt_lightflags
|
||||||
|
- Handles Half-Life styled light_environment entities
|
||||||
![Screenshot](docs/screen.jpg)
|
- New material keys: vmap_lightLinear, vmap_lightLinearFade
|
||||||
|
- Support for target-less spotlights
|
||||||
## Editor Changes
|
- Explicit support for func_detail, func_detail_illusionary
|
||||||
- Valve 220 format is used **top to bottom**, **imported & exported**, with texture coords handled internally the same way, including the compiler
|
- Support for misc_prefab (including other .map files)
|
||||||
- Integration with our **own material format** (no more giant .shader files)
|
- vmap_remapMaterial/q3map_remapShader can carry over surface flags now
|
||||||
- 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
|
- Support for entity key: _entsurfaceflags, so surfaces can override their surfaceflags
|
||||||
- Gracefully deals with duplicate entity attribute key/value pairs, to support features like Source Engine style **Input/Output system** for triggers
|
- Support for entity key: _entcontentflags, so brushes can override their contentflags
|
||||||
- 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!
|
|
||||||
|
|
||||||
## Compiling
|
## Compiling
|
||||||
To compile on a standard GNU/Linux system:
|
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.
|
On BSD you should probably use GNU make right now.
|
||||||
Clang should also be supported, pass `CC=clang and CXX=clang++` if you want to use it.
|
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:
|
On NT you'll have to jump through a lot more hoops, here's the gist:
|
||||||
|
|
||||||
1. MSYS2: https://www.msys2.org/
|
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
|
3. boot into the Mingw64 shell, don't use the stock MSYS2 shell
|
||||||
4. run make and it should build everything, in theory
|
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.**
|
**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
|
## Dependencies
|
||||||
* GNU make
|
* GNU make
|
||||||
* gcc-core
|
* gcc-core
|
||||||
* gcc-c++
|
* gcc-c++
|
||||||
* gtk2-devel
|
* glib2-devel
|
||||||
* gtkglext-devel
|
|
||||||
* libxml2-devel
|
* libxml2-devel
|
||||||
* libjpeg8-devel
|
* libjpeg8-devel
|
||||||
|
* libpng-devel
|
||||||
* minizip-devel
|
* minizip-devel
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
**As mentioned before, if you need help with this: you're on your own.**
|
**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
BIN
icon.png
Binary file not shown.
Before Width: | Height: | Size: 64 KiB |
|
@ -1,52 +1,16 @@
|
||||||
|
|
||||||
all:
|
all:
|
||||||
cd cmdlib && $(MAKE)
|
|
||||||
cd container && $(MAKE)
|
|
||||||
cd ddslib && $(MAKE)
|
cd ddslib && $(MAKE)
|
||||||
cd debugging && $(MAKE)
|
|
||||||
cd etclib && $(MAKE)
|
cd etclib && $(MAKE)
|
||||||
cd filematch && $(MAKE)
|
cd filematch && $(MAKE)
|
||||||
cd generic && $(MAKE)
|
|
||||||
cd gtkutil && $(MAKE)
|
|
||||||
cd l_net && $(MAKE)
|
cd l_net && $(MAKE)
|
||||||
cd math && $(MAKE)
|
|
||||||
cd mathlib && $(MAKE)
|
cd mathlib && $(MAKE)
|
||||||
#cd md5lib && $(MAKE)
|
|
||||||
cd memory && $(MAKE)
|
|
||||||
cd modulesystem && $(MAKE)
|
|
||||||
cd os && $(MAKE)
|
|
||||||
cd picomodel && $(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:
|
clean:
|
||||||
cd cmdlib && $(MAKE) clean
|
|
||||||
cd container && $(MAKE) clean
|
|
||||||
cd ddslib && $(MAKE) clean
|
cd ddslib && $(MAKE) clean
|
||||||
cd debugging && $(MAKE) clean
|
|
||||||
cd etclib && $(MAKE) clean
|
cd etclib && $(MAKE) clean
|
||||||
cd filematch && $(MAKE) clean
|
cd filematch && $(MAKE) clean
|
||||||
cd generic && $(MAKE) clean
|
|
||||||
cd gtkutil && $(MAKE) clean
|
|
||||||
cd l_net && $(MAKE) clean
|
cd l_net && $(MAKE) clean
|
||||||
cd math && $(MAKE) clean
|
|
||||||
cd mathlib && $(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 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
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
101
libs/cmdlib.h
101
libs/cmdlib.h
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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 );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
266
libs/convert.h
266
libs/convert.h
|
@ -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
|
|
|
@ -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
|
|
|
@ -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 );
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
|
|
306
libs/eclasslib.h
306
libs/eclasslib.h
|
@ -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
|
|
718
libs/entitylib.h
718
libs/entitylib.h
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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 ) );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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, ¤t_x, ¤t_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);
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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));
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
Loading…
Reference in a new issue