Finish the project! Added GUI menu for setting the parameters values

master
Andrey2470T 2021-05-05 19:48:08 +03:00
parent 6590a35985
commit adc5fac8b3
289 changed files with 48279 additions and 167 deletions

402
IrrExtensions/Incrementor.h Normal file
View File

@ -0,0 +1,402 @@
/*
(c) 2012-2013 Nicolaus Anderson
Created: Dec 24, 2012
Modified Nov 11, 2019
Incrementor - A simple incrementing class for keeping track of changes in a value
with fewer keystrokes.
*/
//#include "stdtypes.h"
#include <irrTypes.h>
typedef irr::s32 stds32;
typedef irr::u32 stdu32;
#ifndef __INCREMENTOR__
#define __INCREMENTOR__
class Inc
{
public:
enum ECycleType
{
/* This incrementor is to act like a boolean value, switching back and forth
between 0 and 1. */
CYC_BOOLEAN = 0,
/* This incrementor must be set to the min value after reaching the max value
or must be set to the max value if decremented from the min value. */
CYC_REPEAT,
/* This incrementor counts up and down like an ordinary integer. */
CYC_DEFAULT
};
private:
stds32 value;
stds32 step;
stds32 min;
stds32 max;
ECycleType cycle;
public:
//! Constructor
Inc(
ECycleType type = CYC_DEFAULT,
stds32 start_val=0, stds32 start_step=1, stds32 start_min=0, stds32 start_max=1
)
: value( start_val ), step( start_step ), min(start_min), max( start_max ), cycle( type )
{}
//! Deconstructor
~Inc() {}
//! Get type of cycle
ECycleType getCycleType()
{
return cycle;
}
//! Set the cycle type directly
void setCycleType( ECycleType type )
{
cycle = type;
}
//! Set the cycle type to the default
void cycleDefault()
{
cycle = CYC_DEFAULT;
}
//! Set the cycle type to boolean
void cycleBoolean()
{
cycle = CYC_BOOLEAN;
}
//! Set the cycle type to repeat
void cycleRepeat()
{
cycle = CYC_REPEAT;
}
//! Checks if out of bounds - fixes if necessary
bool outOfBounds()
{
switch ( cycle )
{
case CYC_BOOLEAN:
if ( value > 1 )
{
value = 0;
return true;
} else if ( value < 0 )
{
value = 1;
return true;
}
break;
case CYC_REPEAT:
if ( value > max )
{
// Wrap around if greater than the max
value = (value - max) + min;
return true;
} else if ( value < min )
{
// Wrap around if greater than the max
value = (value - max) + min;
return true;
}
default:
if ( value < min || value > max )
return true;
break;
}
return false;
}
//******* Getters and setters **********
stds32& Val()
{
return value;
}
stdu32 uInt()
{
return (stdu32)value;
}
stds32& getStep()
{
return step;
}
stds32& getMin()
{
return min;
}
stds32& getMax()
{
return max;
}
void setVal( stds32 new_val )
{
value = new_val;
}
void setStep( stds32 new_step )
{
step = new_step;
}
void setMin( stds32 new_min )
{
min = new_min;
clampVal();
}
void setMax( stds32 new_max )
{
max = new_max;
clampVal();
}
void setMinShiftMax( stds32 new_min )
{
max += new_min - min;
min = new_min;
clampVal();
}
void setMaxShiftMin( stds32 new_max )
{
min += new_max - max;
max = new_max;
clampVal();
}
void setRange( stds32 new_min, stds32 new_max )
{
min = new_min;
max = new_max;
clampVal();
}
// Range modifiers
#ifdef __RANGE_CLASS__
Range<stds32> getRange()
{
return Range<stds32>( min, max );
}
void setRange ( Range<stds32>& range )
{
min = range.start;
max = range.end;
clampVal();
}
Range<stds32>& operator= ( Range<std32>& range )
{
min = range.start;
max = range.end;
clampVal();
return *this;
}
#endif
void restart()
{
value = min;
}
void clampVal()
{
if ( min > max )
{
stds32 m = min;
min = max;
max = m;
}
if ( value < min )
value = min;
else if ( max < value )
value = max;
}
// ********* Shortcut operators ***********
bool operator++ ()
{
switch( cycle )
{
case CYC_BOOLEAN:
value++;
break;
case CYC_REPEAT:
if ( value == max )
{
value = min;
return true;
} else {
value += step;
}
break;
default:
value += step;
}
return outOfBounds();
}
bool operator++ ( stds32 )
{
return ++(*this);
}
bool operator-- ()
{
switch( cycle )
{
case CYC_BOOLEAN:
value--;
break;
case CYC_REPEAT:
if ( value == min )
{
value = max;
return true;
} else {
value -= step;
}
break;
default:
value -= step;
}
return outOfBounds()
}
bool operator-- ( stds32 )
{
return --(*this);
}
bool operator==( Inc& other )
{
return value == other.value;
}
bool operator>( Inc& other )
{
return value > other.value;
}
bool operator>=( Inc& other )
{
return value >= other.value;
}
bool operator<( Inc& other )
{
return value < other.value;
}
bool operator<=( Inc& other )
{
return value <= other.value;
}
Inc& operator=( Inc& other )
{
return copy(other);
}
Inc& copy( Inc& other )
{
value = other.value;
step = other.step;
min = other.min;
max = other.max;
cycle = other.cycle;
return *this;
}
//****** assignment operators *******
Inc& operator+=( Inc& other )
{
value += other.value;
return *this;
}
Inc& operator-=( Inc& other )
{
value -= other.value;
return *this;
}
Inc& operator=( stds32 val )
{
value = val;
return *this;
}
Inc& operator+=( stds32 val )
{
value += val;
return *this;
}
Inc& operator-=( stds32 val )
{
value -= val;
return *this;
}
Inc& operator=( stdu32 val )
{
value = (stds32)val;
return *this;
}
Inc& operator+=( stdu32 val )
{
value += (stds32)val;
return *this;
}
Inc& operator-=( stdu32 val )
{
value -= (stds32)val;
return *this;
}
};
#endif // define __INCREMENTOR__

View File

@ -0,0 +1,362 @@
/*
(c) 2012-2013 Nicolaus Anderson
Generated from Incrementer.h on: Jan 1, 2012
Modified Nov 11, 2019
Incrementor - A simple incrementing class for keeping track of changes in a value
with fewer keystrokes.
*/
#ifndef __INCREMENTOR__
#define __INCREMENTOR__
template<class Num>
class Inc
{
public:
enum ECycleType
{
/* This incrementor is to act like a boolean value, switching back and forth
between 0 and 1. */
CYC_BOOLEAN = 0,
/* This incrementor must be set to the min value after reaching the max value
or must be set to the max value if decremented from the min value. */
CYC_REPEAT,
/* This incrementor counts up and down like an ordinary integer. */
CYC_DEFAULT
};
private:
Num value;
Num step;
Num min;
Num max;
ECycleType cycle;
public:
//! Constructor
Inc(
ECycleType type = CYC_DEFAULT,
Num start_val=0, Num start_step=1, Num start_min=0, Num start_max=1
)
: value( start_val ), step( start_step ), min(start_min), max( start_max ), cycle( type )
{}
//! Deconstructor
~Inc() {}
//! Get type of cycle
ECycleType getCycleType()
{
return cycle;
}
//! Set the cycle type directly
void setCycleType( ECycleType type )
{
cycle = type;
}
//! Set the cycle type to the default
void cycleDefault()
{
cycle = CYC_DEFAULT;
}
//! Set the cycle type to boolean
void cycleBoolean()
{
cycle = CYC_BOOLEAN;
}
//! Set the cycle type to repeat
void cycleRepeat()
{
cycle = CYC_REPEAT;
}
//! Checks if out of bounds - fixes if necessary
bool outOfBounds()
{
switch ( cycle )
{
case CYC_BOOLEAN:
if ( value > 1 )
{
value = 0;
return true;
} else if ( value < 0 )
{
value = 1;
return true;
}
break;
case CYC_REPEAT:
if ( value > max )
{
// Wrap around if greater than the max
value = (value - max) + min;
return true;
} else if ( value < min )
{
// Wrap around if greater than the max
value = (value - max) + min;
return true;
}
default:
if ( value < min || value > max )
return true;
break;
}
return false;
}
//******* Getters and setters **********
Num& Val()
{
return value;
}
Num& getStep()
{
return step;
}
Num& getMin()
{
return min;
}
Num& getMax()
{
return max;
}
void setVal( Num new_val )
{
value = new_val;
}
void setStep( Num new_step )
{
step = new_step;
}
void setMin( Num new_min )
{
min = new_min;
clampVal();
}
void setMax( Num new_max )
{
max = new_max;
clampVal();
}
void setMinShiftMax( Num new_min )
{
max += new_min - min;
min = new_min;
clampVal();
}
void setMaxShiftMin( Num new_max )
{
min += new_max - max;
max = new_max;
clampVal();
}
void setRange( Num new_min, Num new_max )
{
min = new_min;
max = new_max;
clampVal();
}
// Range modifiers
#ifdef __RANGE_CLASS__
Range<Num> getRange()
{
return Range<Num>( min, max );
}
void setRange( const Range<Num>& range )
{
min = range.start;
max = range.end;
clampVal();
}
Range<Num>& operator= ( const Range<Num>& range )
{
min = range.start;
max = range.end;
clampVal();
return *this;
}
#endif
void restart()
{
value = min;
}
void clampVal()
{
if ( min > max )
{
Num m = min;
min = max;
max = m;
}
if ( value < min )
value = min;
else if ( max < value )
value = max;
}
// ********* Shortcut operators ***********
bool operator++ ()
{
switch( cycle )
{
case CYC_BOOLEAN:
value++;
break;
case CYC_REPEAT:
if ( value == max )
{
value = min;
return true;
} else {
value += step;
}
break;
default:
value += step;
}
return outOfBounds();
}
bool operator-- ()
{
switch( cycle )
{
case CYC_BOOLEAN:
value--;
break;
case CYC_REPEAT:
if ( value == min )
{
value = max;
return true;
} else {
value -= step;
}
break;
default:
value -= step;
}
return outOfBounds();
}
bool operator==( Inc<Num>& other )
{
return value == other.value;
}
bool operator>( Inc<Num>& other )
{
return value > other.value;
}
bool operator>=( Inc<Num>& other )
{
return value >= other.value;
}
bool operator<( Inc<Num>& other )
{
return value < other.value;
}
bool operator<=( Inc<Num>& other )
{
return value <= other.value;
}
Inc<Num>& operator=( Inc<Num>& other )
{
return copy(other);
}
Inc<Num>& copy( Inc<Num>& other )
{
value = other.value;
step = other.step;
min = other.min;
max = other.max;
cycle = other.cycle;
return *this;
}
//****** assignment operators *******
Inc<Num>& operator+=( Inc<Num>& other )
{
value += other.value;
return *this;
}
Inc<Num>& operator-=( Inc<Num>& other )
{
value -= other.value;
return *this;
}
Inc<Num>& operator=( Num val )
{
value = val;
return *this;
}
Inc<Num>& operator+=( Num val )
{
value += val;
return *this;
}
Inc<Num>& operator-=( Num val )
{
value -= val;
return *this;
}
};
#endif // define __INCREMENTOR__

222
IrrExtensions/Range.h Normal file
View File

@ -0,0 +1,222 @@
/*
Range class
(c) Nicolaus Anderson
Created Jan 10, 2013
Modified Nov 8, 2019
License: zlib
*/
#ifndef __RANGE_CLASS__
#define __RANGE_CLASS__
template<class T>
class Range
{
public:
T start;
T end;
Range<T>()
{
start = 0;
end = 0;
}
Range<T>( T new_start, T new_end )
{
start = new_start;
end = new_end;
}
inline T Length()
{
return end - start;
}
operator T ()
{
return Length();
}
//------- division
T operator/ ( T& value )
{
if ( value != 0 )
return Length()/value;
return 0;
}
Range<T>& operator/= ( T& value )
{
end = start + Length()/value;
return *this;
}
//------- multiplication
T operator* ( Range<T>& other )
{
return Length()*other.Length();
}
T operator* ( T& value )
{
return Length()*value;
}
Range<T>& operator*= ( T& value )
{
end = start + Length()*value;
return *this;
}
//------- addition
//! Add ranges
/* Returns the union of two ranges */
Range<T> operator+ ( Range<T>& other )
{
return Range<T>(
(start < other.start)? start : other.start,
(end > other.end)? end : other.end
);
}
//! Add value
/* Returns the length of the range plus the value */
T operator+ ( T& value )
{
return Length() + value;
}
//------- other
//! Extend range
/* Extends the range by the given amount while
returning the range for inline usage. */
Range<T>& extend( T& value )
{
end += value;
return *this;
}
//! In range
/* Indicates if a given value is in the range.
\param value - The number in question.
\param bound_inclusive - Whether the bounds should be
included in the range. */
bool inRange( T& value, bool bound_inclusive=true )
{
if ( bound_inclusive )
return start <= value && value <= end;
else return start < value && value < end;
}
// ***************** With other types *******************
template<class T2>
inline T2 Length()
{
return (T2)(end - start);
}
template<class T2>
operator T2 ()
{
return (T2)Length();
}
//-------- division
template<class T2>
T operator/ ( T2& value )
{
if ( value != 0 )
return Length()/(T)value;
return 0;
}
template<class T2>
Range<T>& operator/= ( T2& value )
{
end = start + Length()/(T)value;
return *this;
}
//------- multiplication
template<class T2>
T operator* ( Range<T2>& other )
{
return Length()*(T)other.Length();
}
template<class T2>
T operator* ( T2& value )
{
return Length()*(T)value;
}
template<class T2>
Range<T>& operator*= ( T2& value )
{
end = start + Length()*(T)value;
return *this;
}
//------- addition
//! Add ranges
/* Returns the union of two ranges */
template<class T2>
Range<T> operator+ ( Range<T2>& other )
{
return Range<T>(
(start < other.start)? start : (T)other.start,
(end > other.end)? end : (T)other.end
);
}
//! Add value
/* Returns the length of the range plus the value */
template<class T2>
T operator+ ( T2& value )
{
return Length() + (T)value;
}
//-------
//! Extend range
/* Extends the range by the given amount while
returning the range for inline usage. */
template<class T2>
Range<T>& extend( T2& value )
{
end += (T)value;
return *this;
}
//! In range
/* Indicates if a given value is in the range.
\param value - The number in question.
\param bound_inclusive - Whether the bounds should be
included in the range. */
template<class T2>
bool inRange( T2& value, bool bound_inclusive=true )
{
if ( (bound_inclusive? start<=value : start<value) )
if ( (bound_inclusive? value<=end : value<end) )
return true;
return false;
}
};
#endif // define __RANGE_CLASS__

3
IrrExtensions/Readme.md Normal file
View File

@ -0,0 +1,3 @@
# Irrlicht Extensions
This is a curated list of extensions for the [Irrlicht engine](http://irrlicht.sourceforge.net). All of this is free code subject to zlib style license unless otherwise specified. Everything in here should work with the latest version of Irrlicht (currently 1.9 unpublished developer version).

111
IrrExtensions/core/circle2d.h Executable file
View File

@ -0,0 +1,111 @@
/*
(c) 2013 Nicolaus Anderson
*/
#include <irrlicht.h>
#ifndef _CIRCLE2D_
#define _CIRCLE2D_
namespace irr
{
namespace core
{
//! Class circle 2D
/*
A 2D circle.
*/
template<class T>
class circle2d
{
public:
vector2d<T> center;
T radius;
circle2d()
: radius( (T)0 )
{}
circle2d( T x, T y, T r )
: center( vector2d<T>(x,y) )
, radius( r )
{}
circle2d( vector2d<T> origin, T r )
: center( origin )
, radius( r )
{}
//! Set
void set( T x, T y, T r )
{
center = vector2d<T>(x,y);
radius = r;
}
//! Set
void set( vector2d<T> origin, T r )
{
center = origin;
radius = r;
}
//! Top point
/* Returns a vector that gives the top-most point on the circle. */
vector2d<T> topPoint()
{
return vector2d<T>( center.X, center.Y + radius);
}
//! Get area
T getArea()
{
return PI * radius * radius;
}
//! Circumference
inline T getCircumference()
{
return 2 * PI * radius;
}
//! Point inside?
bool isPointInside( vector2d<T> point )
{
return ( point - center ).getLengthSQ() <= radius * radius;
}
//! Get horizon
/* Returns the horizontal secant line of the circle at the given
distance from the top.
The line goes from the left side of the circle to the right side. */
line2d<T> getHorizon( T distDown )
{
line2d<T> ret;
ret.start.Y = center.Y + radius - distDown;
ret.end.Y = ret.start.Y;
ret.end.X = (T) squareroot( (irr::f64)
( radius * radius ) - ret.start.Y
);
ret.start.X = - ret.end.X; // get the negative of the sqrt
// correct origin offset
ret.start.X += center.X;
ret.end.X += center.X;
return ret;
}
};
typedef circle2d<irr::s32> circle2di;
typedef circle2d<irr::f32> circle2df;
} // end namespace core
} // end namespace irr
#endif // #ifndef _CIRCLE2D_

152
IrrExtensions/core/irrptr.h Executable file
View File

@ -0,0 +1,152 @@
// By Nicolaus Anderson, 2018
// Based on code posted by Ethon for free on Irrlicht
// Thanks Ethon!
#include <type_traits>
#include <IReferenceCounted.h>
#ifndef __IRRPTR_H__
#define __IRRPTR_H__
// Uncomment to enable
//#define IRRPTR_CHECK_ACCESS
#ifdef IRRPTR_CHECK_ACCESS
class IrrPtrAccessNullException {};
#endif
namespace irr {
namespace tools {
template<typename ObjectType>
class irrptr : std::enable_if< std::is_base_of< irr::IReferenceCounted, ObjectType >::value >
{
public:
typedef typename std::remove_pointer< ObjectType >::type element_type;
typedef element_type* pointer;
typedef element_type const* const_pointer;
irrptr()
: dataptr(nullptr)
{}
irrptr( const irrptr<element_type>& other )
: dataptr( other.dataptr )
{
grab();
}
irrptr<element_type>&
operator= ( irrptr<element_type>& other ) {
set(other.dataptr);
return *this;
}
~irrptr() {
drop();
}
void
set( pointer data ) {
if ( dataptr == data )
return;
drop();
if ( data == 0 ) // Force nullptr usage
dataptr = nullptr;
else
dataptr = data;
grab();
}
void
share( irrptr<element_type>& other ) {
if ( dataptr == other.dataptr )
return;
drop();
dataptr = other.dataptr;
grab();
}
void
swap( irrptr<element_type>& other ) {
pointer p = other.dataptr;
other.dataptr = dataptr;
dataptr = p;
}
void
dump() {
drop();
}
void
quiet_dump() {
// No drop
dataptr = nullptr;
}
pointer
get() {
return dataptr;
}
const_pointer
get() const
{
return dataptr;
}
element_type&
access()
{
#ifdef IRRPTR_CHECK_ACCESS
if ( !dataptr )
throw IrrPtrAccessNullException();
#endif
return *dataptr;
}
element_type const&
access() const
{
#ifdef IRRPTR_CHECK_ACCESS
if ( !dataptr )
throw IrrPtrAccessNullException();
#endif
return *dataptr;
}
explicit operator bool() const
{
return (dataptr != nullptr);
}
protected:
void grab() {
if ( dataptr )
dataptr->grab();
}
void drop() {
if ( dataptr )
dataptr->drop();
}
private:
pointer dataptr;
};
}}
namespace std
{
template<class ObjectType>
void swap( ::irr::tools::irrptr<ObjectType>& p1,
::irr::tools::irrptr<ObjectType>& p2)
{
p1.swap(p2);
}
}
#endif // _IRRPTR_HPP__

398
IrrExtensions/core/triangle2d.h Executable file
View File

@ -0,0 +1,398 @@
/*
(c) 2013 Nicolaus Anderson
*/
#include <irrlicht.h>
#ifndef _TRIANGLE2D_
#define _TRIANGLE2D_
namespace irr
{
namespace core
{
//! Class triangle 2D
/*
A 2D triangle.
*/
template<class T>
class triangle2d
{
public:
vector2d<T> pt1;
vector2d<T> pt2;
vector2d<T> pt3;
triangle2d<T>()
{}
triangle2d<T>(
vector2d<T> point1,
vector2d<T> point2,
vector2d<T> point3
)
: pt1( point1 )
, pt2( point2 )
, pt3( point3 )
{}
triangle2d<T> (
T p1x, T p1y,
T p2x, T p2y,
T p3x, T p3y
)
: pt1( vector2d<T>( p1x, p1y ) )
, pt2( vector2d<T>( p2x, p2y ) )
, pt3( vector2d<T>( p3x, p3y ) )
{}
//! Set
/* Sets the triangle. */
void set(
vector2d<T> point1,
vector2d<T> point2,
vector2d<T> point3
)
{
pt1 = point1;
pt2 = point2;
pt3 = point3;
}
//! Set
/* Sets the triangle. */
void set(
T p1x, T p1y,
T p2x, T p2y,
T p3x, T p3y
)
{
pt1 = vector2d<T>(p1x,p1y);
pt2 = vector2d<T>(p2x,p2y);
pt3 = vector2d<T>(p3x,p3y);
}
//! Top point
/* Returns the address of the top point.
Default return is point 1. */
vector2d<T>& topPoint()
{
if ( pt3.Y > pt2.Y )
{
if ( pt3.Y > pt1.Y )
return pt3;
} else {
if ( pt2.Y > pt1.Y )
return pt2;
}
return pt1;
}
//! Top point index
/* Returns which of the 3 points is the highest
(default return is 1). */
irr::u32 topPointIndex()
{
if ( pt3.Y > pt2.Y )
{
if ( pt3.Y > pt1.Y )
return 3;
} else {
if ( pt2.Y > pt1.Y )
return 2;
}
return 1;
}
//! Set highest point to first
/* Sets the highest point to be the first of the three points. */
void setHighestToFirst()
{
vector2d<T> temp;
if ( pt3.Y > pt2.Y )
{
if ( pt3.Y > pt1.Y )
swap( pt1, pt3 );
} else {
if ( pt2.Y > pt1.Y )
swap( pt1, pt2 );
}
// Else: no change
}
//! Make triangle clockwise
/* Restore the triangle to a clockwise triangle. */
void makeCW()
{
//irr::core::vector2d<T> v12;
//irr::core::vector2d<T> v13;
//irr::core::vector2d<t> v13d;
// Check for equality
if ( pt1 == pt2 || pt1 == pt3 || pt2 == pt3
|| pt1.isBetweenPoints(pt2,pt3)
|| pt2.isBetweenPoints(pt1,pt3)
|| pt3.isBetweenPoints(pt1,pt2)
)
return;
// Set the highest vector to the first one
setHighestToFirst();
// This means only points 2 and 3 are variables
/* For clockwise rotation, 2 must be right of 3.
Switch them if this is not the case. */
if (
(pt3.Y - pt1.Y)*(pt2.X - pt1.X) - (pt2.Y - pt1.Y)*(pt3.X - pt1.X)
< 0
)
{
swap( pt2, pt3 );
}
//v12 = pt2 - pt1;
//v13 = pt3 - pt1;
//// Vertical line - easy comparison
//if ( v13.X == 0 )
//{
// if ( v12.X < 0 )
// swap( pt2, pt3 );
// return;
//}
///* Construct a vector the length of v13 along the x axis. */
//v13d = irr::core::vector2d<T>(
// v13.getLength(),
// 0
// );
///* Subtract this vector from the vector between points 1 and 2.
//This will give us the same situation as above. */
//if ( (v12 - v13d).X < 0 )
//{
// swap( pt2, pt3 );
//}
}
//! Make triangle counter clockwise
/* Restore the triangle to a counter-clockwise triangle. */
void makeCCW()
{
makeCW();
vector2d<T> temp = pt3;
pt3 = pt2;
pt2 = temp;
}
//! Get altitude
/* */
// To do
//! Get area
/* Returns the area of the triangle. */
T getArea()
{
// Can't do this with 2D vectors:
//return
// irr::core::abs_(
// ( (pt2 - pt1).crossProduct(pt3 - pt2) ).getLength()
// ) /(T)2;
return
(
(pt2 - pt1).getLength() * (pt3 - pt2).getLength()
) / (T)2;
}
//! Point inside?
/* Indicates if the point is within the triangle.
Assumes a clockwise triangle.
If you want to keep the original triangle, make a copy of it
and call makeCW() on the copy. */
bool isPointInside( vector2d<T> point )
{
/* Points are automatically disqualified if they are
higher than all of the points or lower than all of them. */
if (
// higher
( point.Y > pt1.Y && point.Y > pt2.Y && point.Y > pt3.Y )
|| // lower
( point.Y < pt1.Y && point.Y < pt2.Y && point.Y < pt3.Y )
)
{
return false;
}
/* If the triangle is flat, then the point need merely be
between any two of the points. */
if ( pt1 == pt2 || pt1 == pt3 || pt2 == pt3 )
{
if (
point.isBetweenPoints(pt2,pt3)
|| point.isBetweenPoints(pt1,pt3)
|| point.isBetweenPoints(pt1,pt2)
)
{
return true;
}
return false;
}
/* For the point to be inside, it must be right of the
vector between pt1 and pt3 and left of the one between
pt1 and pt2. */
// What is commented out is too time-consuming
//line2d<T> line12( pt1, pt2 );
//line2d<T> line13( pt2, pt3 );
//vector2d<T> near12
// = line12.getClosestPoint( point );
//if ( near12.X < point.X )
// return false;
//vector2d<T> near13
// = line13.getClosestPoint( point );
//if ( near13.X > point.X )
// return false;
// Must be inside
//return true;
/* Point must be between the ends of the horizon. */
line2d<T> horiz = getHorizon( point.Y );
if ( horiz.start.X =< point.X
&& point.X <= horiz.end.X )
{
return true;
}
return false;
}
//! Get horizon
/* Returns the horizontal line between the vectors that go between
points 1 and 2 and the points 1 and 3. The vector always starts from
the left side of the triangle and goes to the right side.
Assumes the triangle has been made clockwise.
\param distDown - The distance from the top to form the line. */
line2d<T> getHorizon( T distDown )
{
line2d<T> ret( pt1, pt1 );
/* Don't bother if the distance down is out of the triagle. */
if ( pt1.Y - distDown < (pt2.Y < pt3.Y)? pt2.Y : pt3.Y )
return ret;
/* Situations:
1) Horizon is above point 2 and 3.
2) Horizon is below point 2 which is above point 3.
3) Horizon is below point 3 which is above point 2.
*/
ret.start.Y = pt1.Y - distDown;
ret.end.Y = pt1.Y - distDown;
// Situation 1?
if ( pt1.Y - distDown >= pt2.Y && pt1.Y - distDown >= pt3.Y )
{
if ( pt3.Y == pt1.Y )
{
ret.start = (pt1.X < pt3.X)? pt1 : pt3;
} else {
ret.start.X =
// delta y * 1/m
(pt1.Y - distDown) * ( pt3.X - pt1.X ) / ( pt3.Y - pt1.Y )
+ pt1.X; // offset to location
}
if ( pt2.Y == pt1.Y )
{
ret.end = (pt1.X > pt2.X)? pt1 : pt2;
} else {
ret.end.X =
// delta y * 1/m
(pt1.Y - distDown) * ( pt2.X - pt1.X ) / ( pt2.Y - pt1.Y )
+ pt1.X; // offset to location
}
return ret;
}
// Situation 2?
if ( pt2.Y >= pt3.Y )
{
if ( pt2.Y == pt3.Y )
{
ret.start = pt3;
ret.end = pt2;
return ret;
}
// pt2.Y != pt3.Y
ret.start.X =
// delta y * 1/m
(pt1.Y - distDown) * ( pt3.X - pt1.X ) / ( pt3.Y - pt1.Y )
+ pt1.X; // offset to location
ret.end.X =
// delta y * 1/m
(pt1.Y - distDown) * ( pt3.X - pt2.X ) / ( pt3.Y - pt2.Y )
+ pt2.X; // offset to location
return ret;
}
// Situation 3
ret.start.X =
// delta y * 1/m
(pt1.Y - distDown) * ( pt2.X - pt3.X ) / ( pt2.Y - pt3.Y )
+ pt3.X; // offset to location
ret.end.X =
// delta y * 1/m
(pt1.Y - distDown) * ( pt2.X - pt1.X ) / ( pt2.Y - pt1.Y )
+ pt1.X; // offset to location
return ret;
}
//! Swap points
/* Swaps the values of the two points. */
inline void swap(
vector2d<T>& point1;
vector2d<T>& point2;
)
{
vector2d<T> temp = point1;
point1 = point2;
point2 = temp;
}
};
typedef triangle2d<irr::s32> triangle2di;
typedef triangle2d<irr::f32> triangle2df;
} // end namespace core
} // end namespace irr
#endif // #ifndef _TRIANGLE2D_

View File

@ -0,0 +1,36 @@
/*
(c) 2013 Nicolaus Anderson
*/
#include <IGUIElement.h>
#ifndef _IANIMATED_GUI_ANIMATOR_
#define _IANIMATED_GUI_ANIMATOR_
namespace irr
{
namespace gui
{
//! class Animated GUI Animator
/* Designed to be used with IAnimGUIElement.
This class is meant to be used during OnPostRender() for changing
the GUI element. */
class IAnimGUIAnimator : virtual public irr::IReferenceCounted
{
public:
//! On Post-Render / Animate
/* This is effectively the same as OnAnimate for ISceneNode
but is so named because it is meant to be called on post-rendering. */
virtual void OnPostRender( irr::u32 timeMs, IGUIElement* element )=0;
//! Cast operator
operator IAnimGUIAnimator*()
{
return (IAnimGUIAnimator*)this;
}
};
}} // end namespaces gui and irr
#endif // #ifndef _IANIMATED_GUI_ANIMATOR_

View File

@ -0,0 +1,89 @@
/*
(c) 2013 Nicolaus Anderson
*/
#include <IGUIElement.h>
#include "IAnimGUIAnimator.h"
#ifndef _IANIMATED_GUI_ELEMENT_
#define _IANIMATED_GUI_ELEMENT_
namespace irr
{
namespace gui
{
//! Class Animated GUI Element
/* Allows GUI elements to be animated. */
class IAnimGUIElement : public IGUIElement
{
protected:
irr::core::list<IAnimGUIAnimator*> Animators;
public:
//! Constructor
/* Merely a callback for the IGUIElement constructor. */
IAnimGUIElement(
EGUI_ELEMENT_TYPE type,
IGUIEnvironment* environment,
IGUIElement* parent,
s32 id,
const core::recti& rectangle
)
: IGUIElement( type, environment, parent, id, rectangle )
{}
//! Add animator
void addAnimator( IAnimGUIAnimator* animator )
{
if ( animator )
{
animator->grab();
Animators.push_back( animator );
}
}
//! Remove animator
void removeAnimator( IAnimGUIAnimator* animator )
{
irr::core::list<IAnimGUIAnimator*>::Iterator it = Animators.begin();
for ( ; it != Animators.end(); ++it )
{
if ( *it == animator )
{
(*it)->drop();
Animators.erase(it);
return;
}
}
}
//! Remove all animators
void clearAnimators()
{
irr::core::list<IAnimGUIAnimator*>::Iterator it = Animators.begin();
while ( it != Animators.end() )
{
(*it)->drop();
Animators.erase(it);
it = Animators.begin();
}
}
//! On Post Render
/* Applies the animators */
virtual void OnPostRender( irr::u32 timeMs )
{
irr::core::list<IAnimGUIAnimator*>::Iterator it;
for ( ; it != Animators.end(); ++it )
{
(*it)->OnPostRender( timeMs, this );
}
IGUIElement::OnPostRender(timeMs);
}
};
}} // end namespaces gui and irr
#endif // #ifndef _IANIMATED_GUI_ELEMENT_

View File

@ -0,0 +1,94 @@
/*
(c) 2013 Nicolaus Anderson
*/
#include "MoveGUIAnimator.h"
#ifndef _MOVE_GUI_ANIMATOR_CPP_
#define _MOVE_GUI_ANIMATOR_CPP_
namespace irr
{
namespace gui
{
MoveGUIAnimator::MoveGUIAnimator(
core::recti* rectangle,
f64 speed,
u32 startTimeMs
)
: ElemRect( rectangle )
, OrigRect( *rectangle )
, TargetRect( *rectangle )
, transitionSpeed( speed )
, startTime( startTimeMs )
{
}
MoveGUIAnimator::~MoveGUIAnimator()
{}
void MoveGUIAnimator::setStartTime( u32 timeMs )
{
if ( inMotion )
return;
startTime = timeMs;
}
void MoveGUIAnimator::OnPostRender( u32 timeMs, IGUIElement* element )
{
// This animator must be started first.
if ( startTime > timeMs )
{
inMotion = false;
return;
}
if ( *ElemRect == TargetRect )
{
inMotion = false;
OrigRect = TargetRect;
return;
}
inMotion = true;
/* Obtain the transition delta for the rectangle based on start time.
Note that the direction of interpolate() is backwards, so the transition
distance is subtracted from 1.0 rather than being used on its own. */
irr::f64 delta =
1.0 - irr::core::clamp(
((irr::f64)(timeMs - startTime)*transitionSpeed),
0.0, 1.0
);
ElemRect->UpperLeftCorner.interpolate(
OrigRect.UpperLeftCorner,
TargetRect.UpperLeftCorner,
delta
);
ElemRect->LowerRightCorner.interpolate(
OrigRect.LowerRightCorner,
TargetRect.LowerRightCorner,
delta
);
}
void MoveGUIAnimator::setTargetRect( core::rect<s32> newTarget )
{
OrigRect = *ElemRect;
TargetRect = newTarget;
}
void MoveGUIAnimator::setImmediateTarget( core::rect<s32> newTarget, u32 timeMs )
{
OrigRect = *ElemRect;
TargetRect = newTarget;
startTime = timeMs;
}
}} // end namespaces gui and irr
#endif // #ifndef _MOVE_GUI_ANIMATOR_CPP_

View File

@ -0,0 +1,73 @@
/*
(c) 2013 Nicolaus Anderson
*/
#include <irrlicht.h>
#include "IAnimGUIAnimator.h"
#ifndef _MOVE_GUI_ANIMATOR_H_
#define _MOVE_GUI_ANIMATOR_H_
namespace irr
{
namespace gui
{
class MoveGUIAnimator : public IAnimGUIAnimator
{
protected:
//! The element rectangle to be changed.
/* Notice that this is a pointer, allowing us to change any rectangle
that is passed to this animator by the GUI element / creator of this
animator. */
core::rect<s32>* ElemRect;
//! Original rectangle.
/* This is the initial rectangle that is to be changed.
Once the animation is complete or its course has been altered,
this is set to the element's current rectangle. */
core::rect<s32> OrigRect;
//! Target rectangle
/* This is the final destination rectangle. */
core::rect<s32> TargetRect;
/* The starting time of this element in milliseconds. */
u32 startTime;
/* Speed of the transition. */
f64 transitionSpeed;
/* In motion.
When this is set to true, the start time cannot be changed
without starting a new animation. */
bool inMotion;
public:
//! Constructor and destructor
MoveGUIAnimator(
core::recti* rectangle,
f64 speed,
u32 startTimeMs
);
~MoveGUIAnimator();
//! Set start time.
/* Sets the animator's start time. Note that this does nothing if
there is an animation that has not been completed yet. */
void setStartTime( u32 timeMs );
//! On Post Render / Animate
virtual void OnPostRender( u32 timeMs, IGUIElement* element );
//! Set target rectangle
void setTargetRect( core::rect<s32> newTarget );
//! Set immediate target (for interrupting a current transition)
void setImmediateTarget( core::rect<s32> newTarget, u32 timeMs );
};
}} // end namespaces gui and irr
#endif // #ifndef _MOVE_GUI_ANIMATOR_H_

View File

@ -0,0 +1,516 @@
// (c) 2014 Nicolaus Anderson
#include "GUIColorEditBox.h"
#include <IGUISkin.h>
#include <IGUIFont.h>
namespace irr {
namespace gui {
GUIColorEditBox::GUIColorEditBox(
IGUIEnvironment* pEnvironment, IGUIElement* pParent, recti pRect, s32 id
)
: IGUIElement( EGUIET_ELEMENT, pEnvironment, pParent, id, pRect )
, color(0xff000000)
, cursorColor(0x0000ddff)
, cursorIdx(0)
, cursorRect(0,0,0,0)
, focusTime(0)
{
Text = L"ff000000";
}
GUIColorEditBox::~GUIColorEditBox()
{}
SColor GUIColorEditBox::getColor()
{
return color;
}
void GUIColorEditBox::setColor( SColor pColor, bool notifyParent )
{
color = pColor;
convertColorToText();
if ( Parent && notifyParent )
{
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_EDITBOX_CHANGED;
Parent->OnEvent(newEvent);
}
}
void
GUIColorEditBox::setText(const wchar_t* text)
{
Text = text;
if ( Text.size() > 6 ) {
Text = Text.subString(0,6);
}
u32 i=0;
for (; i < 6; ++i) {
if ( Text[i] < '0' )
Text[i] = '0';
else if ( Text[i] > 'f' )
Text[i] = 'f';
}
convertTextToColor();
}
bool GUIColorEditBox::OnEvent( const SEvent& event )
{
SEvent newEvent;
if ( isEnabled() && isVisible() )
switch( event.EventType )
{
case EET_MOUSE_INPUT_EVENT:
if ( event.MouseInput.isLeftPressed() )
return setCursorIndexFromPosition(
vector2di(event.MouseInput.X, event.MouseInput.Y)
);
return false;
case EET_KEY_INPUT_EVENT:
if ( event.KeyInput.PressedDown )
if ( insertChar( event.KeyInput.Key, event.KeyInput.Char ) )
{
if ( Parent )
{
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_EDITBOX_CHANGED;
Parent->OnEvent(newEvent);
}
return true;
}
break;
case EET_GUI_EVENT:
switch ( event.GUIEvent.EventType )
{
case EGET_ELEMENT_FOCUSED:
updateCursorRect();
break;
case EGET_ELEMENT_FOCUS_LOST:
break;
default: break;
}
default: break;
}
return IGUIElement::OnEvent(event);
}
void GUIColorEditBox::draw()
{
if ( !isVisible() )
return;
IGUISkin* skin = Environment->getSkin();
if ( Environment->getFocus() == this )
{
skin->draw3DSunkenPane(
this,
skin->getColor(EGDC_EDITABLE),
true, true,
AbsoluteRect, &AbsoluteClippingRect );
skin->getFont(irr::gui::EGDF_DEFAULT)->draw(
Text,
AbsoluteRect,
skin->getColor(EGDC_BUTTON_TEXT),
true, true, // center
&AbsoluteClippingRect
);
// Draw transitioning-color cursor
u32 ft = focusTime % 1000;
if ( ft > 500 )
{
ft = 1000 - ft;
}
ft /= 4;
cursorColor.setAlpha( core::clamp( ft, (u32)0, (u32)255 ) );
recti cR = cursorRect + AbsoluteRect.UpperLeftCorner;
skin->draw2DRectangle(
this,
cursorColor,
cR,
&AbsoluteClippingRect
);
} else {
skin->draw3DSunkenPane(
this,
skin->getColor(EGDC_GRAY_EDITABLE),
true, true,
AbsoluteRect, &AbsoluteClippingRect );
// Draw grayed text
skin->getFont()->draw(
Text,
AbsoluteRect,
skin->getColor(EGDC_GRAY_TEXT),
true, true, // center
&AbsoluteClippingRect
);
}
}
void GUIColorEditBox::OnPostRender(u32 timeMs)
{
focusTime = timeMs;
}
bool GUIColorEditBox::setCursorIndexFromPosition( vector2di pPos )
{
// Actual location
vector2di cursorPos = pPos - AbsoluteRect.UpperLeftCorner;
if ( ! AbsoluteClippingRect.isPointInside( pPos ) )
return false;
// Calculate by starting with the start position
dimension2du textSize = Environment->getSkin()->getFont()->getDimension(Text.c_str());
cursorPos.X -= (AbsoluteRect.getWidth() - textSize.Width)/2;
cursorPos.Y -= (AbsoluteRect.getHeight() - textSize.Height)/2;
// Cursor must be in text area
if ( cursorPos.X < 0 || (u32)cursorPos.X >= textSize.Width
|| cursorPos.Y < 0 || (u32)cursorPos.Y >= textSize.Height)
{
return false;
}
// KEEP for FAST version
//cursorIdx = u32( (cursorPos.X * 8) / textSize.Width );
cursorIdx = Environment->getSkin()->getFont()->getCharacterFromPos(Text.c_str(), cursorPos.X);
updateCursorRect();
return true;
}
void GUIColorEditBox::updateCursorRect()
{
dimension2du textSize = Environment->getSkin()->getFont()->getDimension(Text.c_str());
vector2di center( RelativeRect.getWidth(), RelativeRect.getHeight() );
center /= 2;
vector2di start = center - vector2di( textSize.Width/2, textSize.Height/2 );
// KEEP THIS FOR FASTER CODE
//cursorRect.UpperLeftCorner.X = start.X + (textSize.Width * cursorIdx)/8 - 1;
//cursorRect.UpperLeftCorner.Y = start.Y;
//cursorRect.LowerRightCorner.X = start.X + (textSize.Width * (cursorIdx+1))/8;
//cursorRect.LowerRightCorner.Y = start.Y + textSize.Height;
s32 indexCoord = 0;
s32 lastIndexCoord = 0;
core::stringw shortText;
if ( cursorIdx > 0 )
{
shortText = Text.subString(0,cursorIdx);
indexCoord = Environment->getSkin()->getFont()->getDimension( shortText.c_str() ).Width;
}
shortText = Text.subString(cursorIdx,1);
lastIndexCoord = Environment->getSkin()->getFont()->getDimension( shortText.c_str() ).Width;
cursorRect.UpperLeftCorner.X = start.X + indexCoord;
cursorRect.UpperLeftCorner.Y = start.Y;
cursorRect.LowerRightCorner.X = start.X + indexCoord + lastIndexCoord;
cursorRect.LowerRightCorner.Y = start.Y + textSize.Height;
//cursorRect.repair(); // Causes (a bug:) box to not appear when cursoxIdx>5
}
bool GUIColorEditBox::insertChar( EKEY_CODE pKeyCode, wchar_t pKey )
{
u32 cursorByte = (7-cursorIdx)*4;
//u32 savedColor = color.color & ( 0xffffffff ^ (0xf0000000 >> cursorByte) );
u32 savedColor = color.color & ( ~ ( 0x0000000f << cursorByte ) );
// Some systems (e.g. X11) fill event.KeyCode.Char correctly for NumPad but still pass the same KeyCode
// as if NumLock were off.
if ( pKey == 0 ) {
switch ( pKeyCode )
{
// Cursor movement
case KEY_HOME:
cursorIdx = 0;
updateCursorRect();
return true;
case KEY_END:
cursorIdx = 7;
updateCursorRect();
return true;
case KEY_DELETE:
clear();
cursorIdx = 0;
updateCursorRect();
return true;
case KEY_LEFT:
if ( cursorIdx > 0 )
--cursorIdx;
updateCursorRect();
return true;
case KEY_RIGHT:
if ( cursorIdx < 7 )
++cursorIdx;
updateCursorRect();
return true;
default:
return false;
}
}
u32 c_bit;
if ( pKey >= L'0' && pKey <= '9' ) {
c_bit = (u32) pKey - L'0';
color.color = (c_bit << cursorByte) | savedColor;
Text[cursorIdx] = pKey;
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
}
switch ( pKeyCode )
{
/*
// Inserting characters
case KEY_KEY_0:
case KEY_NUMPAD0:
color.color = savedColor;
Text[cursorIdx] = '0';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_1:
case KEY_NUMPAD1:
color.color = (1 << cursorByte) | savedColor;
Text[cursorIdx] = '1';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_2:
case KEY_NUMPAD2:
color.color = (2 << cursorByte) | savedColor;
Text[cursorIdx] = '2';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_3:
case KEY_NUMPAD3:
color.color = (3 << cursorByte) | savedColor;
Text[cursorIdx] = '3';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_4:
case KEY_NUMPAD4:
color.color = (4 << cursorByte) | savedColor;
Text[cursorIdx] = '4';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_5:
case KEY_NUMPAD5:
color.color = (5 << cursorByte) | savedColor;
Text[cursorIdx] = '5';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_6:
case KEY_NUMPAD6:
color.color = (6 << cursorByte) | savedColor;
Text[cursorIdx] = '6';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_7:
case KEY_NUMPAD7:
color.color = (7 << cursorByte) | savedColor;
Text[cursorIdx] = '7';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_8:
case KEY_NUMPAD8:
color.color = (8 << cursorByte) | savedColor;
Text[cursorIdx] = '8';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_9:
case KEY_NUMPAD9:
color.color = (9 << cursorByte) | savedColor;
Text[cursorIdx] = '9';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
*/
case KEY_KEY_A:
// same as: color.color = (0xa0 << cursorByte) | savedColor;
color.color = (10 << cursorByte) | savedColor;
Text[cursorIdx] = 'a';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_B:
color.color = (11 << cursorByte) | savedColor;
Text[cursorIdx] = 'b';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_C:
color.color = (12 << cursorByte) | savedColor;
Text[cursorIdx] = 'c';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_D:
color.color = (13 << cursorByte) | savedColor;
Text[cursorIdx] = 'd';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_E:
color.color = (14 << cursorByte) | savedColor;
Text[cursorIdx] = 'e';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
case KEY_KEY_F:
color.color = (15 << cursorByte) | savedColor;
Text[cursorIdx] = 'f';
++cursorIdx;
if ( cursorIdx > 7 ) cursorIdx = 0;
updateCursorRect();
return true;
default: break;
}
return false;
}
void GUIColorEditBox::convertTextToColor()
{
color.color = 0;
u32 i;
if ( Text.size() != 8 ) Text = L"ff000000"; // User used setText(), so fix it.
for ( i=0; i < 8; i++ )
{
if ( Text[i] <= 'f' && Text[i] >= 'a' )
color.color |= (Text[i] - 'a' + 10) >> (i*4);
else if ( Text[i] <= '9' && Text[i] >= '0' )
color.color |= (Text[i] - '0') >> (i*4);
// else
// User must have used setText()
}
}
void GUIColorEditBox::convertColorToText()
{
u32 i;
u8 chr;
if ( Text.size() != 8 ) Text = L"ff000000"; // User used setText(), so fix it.
for ( i=0; i < 8; i++ )
{
/* On this computer, when going FROM u32 TO u8, you have to shift the
bits to the right. I will probably need to have this check for endianess
if this is going to be portable code. */
chr = u8( ( color.color & (0xf0000000 >> (i*4)) ) >> ((7-i)*4) );
if ( chr > 9 )
Text[i] = c8( (chr-10) + 'a' );
else
Text[i] = c8( chr + '0' );
}
}
void GUIColorEditBox::clear()
{
color.color = 0;
Text = L"00000000";
}
void GUIColorEditBox::serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options
)
{
IGUIElement::serializeAttributes(out,options);
out->addColor("Color", color);
}
void GUIColorEditBox::deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options
)
{
IGUIElement::deserializeAttributes(in,options);
bool notifyParentOfEvent = false;
if ( in->existsAttribute("NotifyParentOfColorChange") ) {
notifyParentOfEvent = in->getAttributeAsBool("NotifyParentOfColorChange");
}
// Override setText()
if ( in->existsAttribute("Color") ) {
setColor( in->getAttributeAsColor("Color", color), notifyParentOfEvent );
}
}
}
}

View File

@ -0,0 +1,95 @@
// (c) 2014 Nicolaus Anderson
#include <irrMath.h>
#include <IGUIElement.h>
#include <IGUIEnvironment.h>
#ifndef GUI_COLOR_EDITBOX_H
#define GUI_COLOR_EDITBOX_H
/* Class GUI Color Edit Box
A GUI Element that accepts only certain user input
(e.g. the character range '0'-'9', 'a'-'f', as well as some
useful editing keys).
The box always contains a valid, HTML-style color, and the
user input is such that it is overwriting, and that way,
8 characters are always present in the edit box.
*/
namespace irr
{
namespace gui
{
using irr::video::SColor;
using irr::core::recti;
using irr::core::vector2di;
using irr::core::dimension2du;
class GUIColorEditBox : public IGUIElement
{
protected:
SColor color, cursorColor;
s32 cursorIdx; // index of the cursor in the text
recti cursorRect;
u32 focusTime;
public:
GUIColorEditBox( IGUIEnvironment* pEnvironment, IGUIElement* pParent, recti pRect, s32 id=-1 );
~GUIColorEditBox();
SColor getColor();
void setColor( SColor pColor, bool notifyParent=true );
// Set the numeric text
virtual void setText(const wchar_t* text);
/* Handles user events.
Because of how this element refreshes, the data/color should NOT
be taken from this element until this element has lost focus,
upon which it will call its parent. */
virtual bool OnEvent( const SEvent& event );
// Draws to the screen
virtual void draw();
// Post rendering (for cursor time)
virtual void OnPostRender(u32 timeMs);
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "colorEditbox"; }
// For completeness, we allow both setText and setColor to set the color
virtual void serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options=0
);
virtual void deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options=0
);
protected:
// Attempts to set the cursor position - Returns whether or not it could
bool setCursorIndexFromPosition( vector2di pPos );
// Sets the cursor rectangle to the cursor position
void updateCursorRect();
// Attempts to insert a character
bool insertChar( EKEY_CODE pKeyCode, wchar_t pKey );
// Internal conversion functions
void convertTextToColor();
void convertColorToText();
// Erase data
void clear();
};
}
}
#endif

View File

@ -0,0 +1,157 @@
// (c) 2014 Nicolaus Anderson
#ifndef GUI_COLOR_SAMPLE_CPP
#define GUI_COLOR_SAMPLE_CPP
#include "GUIColorSample.h"
#include <IVideoDriver.h>
namespace irr {
namespace gui {
using irr::core::vector2d;
using irr::video::IVideoDriver;
GUIColorSample::GUIColorSample( IGUIEnvironment* pEnvironment, IGUIElement* pParent, recti pRect, s32 id )
: IGUIElement( EGUIET_ELEMENT, pEnvironment, pParent, id, pRect )
, upperLeft(0)
, upperRight(0)
, lowerLeft(0)
, lowerRight(0)
, drawBorder(false)
, borderWidth(3)
// , colorArea(pRect)
{
colorArea = AbsoluteClippingRect;
}
void GUIColorSample::setDrawBorder(bool yes)
{
drawBorder = yes;
colorArea = AbsoluteClippingRect;
if ( drawBorder )
{
colorArea.UpperLeftCorner += vector2d<s32>(borderWidth);
colorArea.LowerRightCorner -= vector2d<s32>(borderWidth);
}
}
void GUIColorSample::updateAbsolutePosition()
{
IGUIElement::updateAbsolutePosition();
colorArea = AbsoluteClippingRect;
if ( drawBorder )
{
colorArea.UpperLeftCorner += vector2d<s32>(borderWidth);
colorArea.LowerRightCorner -= vector2d<s32>(borderWidth);
}
}
void GUIColorSample::showOneColor( SColor pColor )
{
upperLeft = pColor;
upperRight = pColor;
lowerLeft = pColor;
lowerRight = pColor;
}
void GUIColorSample::showTwoColors( SColor pTopLeft, SColor pBottomRight, bool horizontal )
{
upperLeft = pTopLeft;
lowerRight = pBottomRight;
if ( horizontal )
{
upperRight = pTopLeft;
lowerRight = pBottomRight;
} else {
upperRight = pBottomRight;
lowerRight = pTopLeft;
}
}
void GUIColorSample::showFourColors( SColor pUpperLeft, SColor pUpperRight, SColor pLowerLeft, SColor pLowerRight )
{
upperLeft = pUpperLeft;
upperRight = pUpperRight;
lowerLeft = pLowerLeft;
lowerRight = pLowerRight;
}
bool GUIColorSample::OnEvent( const SEvent& event )
{
/* This element cannot be set in focus. */
if ( !isVisible() || !isEnabled() )
if ( event.EventType == EET_GUI_EVENT
&& event.GUIEvent.Caller == this
&& event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED )
{
if ( Parent )
Environment->setFocus( Parent );
else
Environment->setFocus(0);
return true;
}
return IGUIElement::OnEvent(event);
}
void GUIColorSample::draw()
{
if ( isVisible() )
{
if ( drawBorder )
{
Environment->getSkin()->draw3DSunkenPane(
this,
Environment->getSkin()->getColor(EGDC_3D_FACE),
true, false,
AbsoluteRect,
&AbsoluteClippingRect
);
}
Environment->getVideoDriver()->draw2DRectangle(
colorArea,
upperLeft, upperRight, lowerLeft, lowerRight,
&AbsoluteClippingRect
);
}
}
void GUIColorSample::serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options
)
{
IGUIElement::serializeAttributes(out,options);
out->addColor("UpperLeftColor", upperLeft);
out->addColor("UpperRightColor", upperRight);
out->addColor("LowerLeftColor", lowerLeft);
out->addColor("LowerRightColor", lowerRight);
out->addBool("DrawBorder", drawBorder);
out->addInt("BorderWidth", borderWidth);
}
void GUIColorSample::deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options
)
{
IGUIElement::deserializeAttributes(in,options);
upperLeft = in->getAttributeAsColor("UpperLeftColor", upperLeft);
upperRight = in->getAttributeAsColor("UpperRightColor", upperRight);
lowerLeft = in->getAttributeAsColor("LowerLeftColor", lowerLeft);
lowerRight = in->getAttributeAsColor("LowerRightColor", lowerRight);
borderWidth = in->getAttributeAsInt("BorderWidth", borderWidth);
setDrawBorder( in->getAttributeAsBool("DrawBorder", drawBorder) );
}
}}
#endif // #ifndef GUI_COLOR_SAMPLE_CPP

View File

@ -0,0 +1,60 @@
// (c) 2014 Nicolaus Anderson
#ifndef GUI_COLOR_SAMPLE_H
#define GUI_COLOR_SAMPLE_H
#include <IGUIElement.h>
#include <IGUIEnvironment.h>
namespace irr {
namespace gui {
using core::recti;
using video::SColor;
/* Just a simple square element that shows one or more
colors, depending on its setting. */
class GUIColorSample : public IGUIElement
{
SColor upperLeft;
SColor upperRight;
SColor lowerLeft;
SColor lowerRight;
bool drawBorder;
s32 borderWidth;
recti colorArea;
/* Note: set enabled to "true" if you want to be able to set this element
to the focus. */
public:
GUIColorSample( IGUIEnvironment* pEnvironment, IGUIElement* pParent, recti pRect, s32 id=-1 );
void setDrawBorder(bool yes);
virtual void updateAbsolutePosition();
void showOneColor( SColor pColor );
void showTwoColors( SColor pTopLeft, SColor pBottomRight, bool horizontal );
void showFourColors( SColor pUpperLeft, SColor pUpperRight, SColor pLowerLeft, SColor pLowerRight );
virtual bool OnEvent( const SEvent& event );
virtual void draw();
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "colorSample"; }
virtual void serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options=0
);
virtual void deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options=0
);
};
}}
#endif // #ifndef GUI_COLOR_SAMPLE_H

View File

@ -0,0 +1,293 @@
// (c) 2015 Nicolaus Anderson
// zlib license
#ifndef GUI_DROPDOWN_SELECTOR_CPP
#define GUI_DROPDOWN_SELECTOR_CPP
#include "GUIDropdownSelector.h"
#include <IGUIButton.h>
#include <IGUIContextMenu.h>
#include <IGUIEnvironment.h>
#include <IGUISpriteBank.h>
#include <IGUISkin.h>
namespace irr {
namespace gui {
using video::SColor;
GUIDropdownSelector::GUIDropdownSelector( IGUIEnvironment* pEnvironment, IGUIElement* pParent, rect<s32> pRect, s32 id )
: IGUIElement( EGUIET_ELEMENT, pEnvironment, pParent, id, pRect )
, dirty( true )
, wasMenuFocus( false )
, iconRect()
{
button = pEnvironment->addButton( rect<s32>(pRect.getSize()), this, -1, L"", L"Click to select" );
button->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
button->setDrawBorder(true);
recalculateAbsolutePosition(false);
menu = pEnvironment->addContextMenu(
AbsoluteRect + core::vector2d<s32>(0, pRect.getHeight() ),
pEnvironment->getRootGUIElement()
);
menu->grab();
menu->setVisible(false);
menu->setCloseHandling( ECMC_HIDE );
menu->setEventParent(this);
s32 h = arrowHeight;
s32 hspace = (AbsoluteRect.getHeight() - h) / 2;
iconRect = rect<s32>(
AbsoluteRect.LowerRightCorner.X - (h + hspace), // upper left x
AbsoluteRect.UpperLeftCorner.Y + hspace, // upper left y
AbsoluteRect.LowerRightCorner.X - hspace, // lower right x
AbsoluteRect.LowerRightCorner.Y - hspace // lower right y
);
}
GUIDropdownSelector::~GUIDropdownSelector()
{
menu->remove(); // Removes from environment
menu->drop();
}
void GUIDropdownSelector::setText( const wchar_t* pText )
{
dirty = true;
button->setText( pText );
}
void GUIDropdownSelector::setToolTipText(const wchar_t* text)
{
button->setToolTipText(text);
}
s32 GUIDropdownSelector::getSelected() const
{
return menu->getSelectedItem();
}
const wchar_t* GUIDropdownSelector::getSelectedText() const
{
s32 i = menu->getSelectedItem();
if ( i != -1 && !dirty )
{
return menu->getItemText( i );
}
return L"";
}
const wchar_t* GUIDropdownSelector::getItemText( u32 pIndex ) const
{
return menu->getItemText( pIndex );
}
void GUIDropdownSelector::setItemText( u32 pIndex, const wchar_t* pText )
{
menu->setItemText( pIndex, pText );
}
void GUIDropdownSelector::setItemEnabled( u32 pIndex, bool pEnable )
{
menu->setItemEnabled( pIndex, pEnable );
}
bool GUIDropdownSelector::isItemEnabled( u32 pIndex ) const
{
return menu->isItemEnabled( pIndex );
}
u32 GUIDropdownSelector::getItemCount() const {
return menu->getItemCount();
}
void GUIDropdownSelector::removeItem( u32 pIndex )
{
menu->removeItem( pIndex );
}
void GUIDropdownSelector::removeAllItems()
{
menu->removeAllItems();
button->setText(L"");
}
void GUIDropdownSelector::addItem( const wchar_t* pText, bool pEnabled )
{
menu->addItem( pText, -1, pEnabled, false, false, false );
if ( menu->getItemCount() == 1 ) // first item
{
button->setText( pText );
}
}
void GUIDropdownSelector::updateAbsolutePosition()
{
IGUIElement::updateAbsolutePosition();
rect<s32> menuRect = menu->getRelativePosition();
s32 mW = menuRect.getWidth();
s32 mH = menuRect.getHeight();
/* Recall, the menu is added to the root GUI element, so its relative position is relative
to the root, and consequently at the NEW absolute position of this element. */
menu->setRelativePosition(
rect<s32>(0,0,mW,mH) + AbsoluteRect.UpperLeftCorner + core::vector2d<s32>( 0, AbsoluteRect.getHeight() )
);
s32 h = arrowHeight;
s32 hspace = (AbsoluteRect.getHeight() - h) / 2;
iconRect = rect<s32>(
AbsoluteRect.LowerRightCorner.X - (h + hspace), // upper left x
AbsoluteRect.UpperLeftCorner.Y + hspace, // upper left y
AbsoluteRect.LowerRightCorner.X - hspace, // lower right x
AbsoluteRect.LowerRightCorner.Y - hspace // lower right y
);
}
bool GUIDropdownSelector::OnEvent( const SEvent& event )
{
if ( ! isVisible() || ! isEnabled() )
return false;
if ( event.EventType != EET_GUI_EVENT )
return false;
switch ( event.GUIEvent.EventType )
{
case EGET_ELEMENT_FOCUSED:
if ( event.GUIEvent.Caller == button )
{
/* Irrlicht's CGUIEnvironment maintains the last GUI focus until the end of its setFocus() method. */
wasMenuFocus = ( Environment->getFocus() == menu );
}
break;
case EGET_BUTTON_CLICKED:
if ( event.GUIEvent.Caller == button )
{
/* Avoid opening the menu if it was already open. */
if ( ! wasMenuFocus )
{
//Parent->bringToFront(this);
menu->setVisible( true );
Environment->getRootGUIElement()->bringToFront(menu);
Environment->setFocus(menu);
return true;
}
wasMenuFocus = false;
return true;
}
break;
case EGET_MENU_ITEM_SELECTED:
if ( event.GUIEvent.Caller == menu )
{
dirty = false;
button->setText( getSelectedText() );
sendGUIEvent( EGET_COMBO_BOX_CHANGED );
return true;
}
default: break;
}
return false;
}
void GUIDropdownSelector::draw()
{
if ( ! isVisible() )
{
menu->setVisible(false); // Ensure an accidentally-opened menu is hidden
return;
}
//IGUIElement::draw();
button->draw();
menu->draw();
// Drawing a down-arrow
u32 dropDownIcon = Environment->getSkin()->getIcon( EGDI_CURSOR_DOWN /*EGDI_DROP_DOWN*/ );
//video::SColor iconColor = Environment->getSkin()->getColor( isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL );
// if too small to draw
if ( iconRect.getWidth() < 0 || iconRect.getHeight() < 0 )
return;
Environment->getSkin()->getSpriteBank()->draw2DSprite( dropDownIcon, iconRect, &AbsoluteClippingRect );
}
void GUIDropdownSelector::sendGUIEvent( EGUI_EVENT_TYPE pEventType, IGUIElement* pElement )
{
if ( ! Parent ) return;
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = pElement;
event.GUIEvent.EventType = pEventType;
Parent->OnEvent( event );
}
void GUIDropdownSelector::serializeAttributes( io::IAttributes* out, io::SAttributeReadWriteOptions* options ) const {
IGUIElement::serializeAttributes(out, options);
out->addInt("Selected", getSelected());
out->addString("SelectedText", getSelectedText());
out->addInt("ItemCount", menu->getItemCount());
u32 i = 0;
for (; i < getItemCount(); ++i) {
core::stringc name("Item");
name += i;
name += "Text";
out->addString(name.c_str(), getItemText(i));
core::stringc label("Item");
label += i;
label += "Enabled";
out->addBool(label.c_str(), isItemEnabled(i));
}
}
void GUIDropdownSelector::deserializeAttributes( io::IAttributes* in, io::SAttributeReadWriteOptions* options ) {
IGUIElement::deserializeAttributes(in, options);
dirty = true;
u32 selected = -1;
s32 itemCount = 0;
s32 i=0;
bool enabled;
//selected = in->getAttributeAsInt("Selected", selected);
// UNAVAILABLE: IContextMenu doesn't allowing setting the Highlighted menu item.
removeAllItems();
itemCount = in->getAttributeAsInt("ItemCount", itemCount);
if ( itemCount > 0 ) {
for (; i < itemCount; ++i) {
core::stringc label("Item");
label += i;
label += "Enabled";
core::stringc name("Item");
name += i;
name += "Text";
enabled = in->getAttributeAsBool(label.c_str(), false);
addItem( in->getAttributeAsStringW(name.c_str()).c_str(), enabled );
}
}
updateAbsolutePosition();
menu->setRelativePosition(AbsoluteRect + core::vector2d<s32>(0, RelativeRect.getHeight() ));
wasMenuFocus = ( Environment->getFocus() == menu );
if ( wasMenuFocus )
Environment->setFocus(0);
}
}}
#endif // #ifndef GUI_DROPDOWN_SELECTOR_CPP

View File

@ -0,0 +1,71 @@
// (c) 2015 Nicolaus Anderson
// zlib license
#ifndef GUI_DROPDOWN_SELECTOR_H
#define GUI_DROPDOWN_SELECTOR_H
#include <IGUIElement.h>
namespace irr {
namespace gui {
class IGUIButton;
class IGUIContextMenu;
using core::rect;
//! GUI Drop-down selector
/*
This is merely a controller for a button and a menu.
The menu is used to select what is displayed on the button.
*/
class GUIDropdownSelector : public IGUIElement
{
IGUIButton* button;
IGUIContextMenu* menu;
bool dirty;
bool wasMenuFocus;
rect<s32> iconRect;
static const s32 arrowHeight = 8;
public:
GUIDropdownSelector( IGUIEnvironment* pEnvironment, IGUIElement* pParent, rect<s32> pRect, s32 id=-1 );
~GUIDropdownSelector();
/* Sets the current text (which may not be in the menu).
Note that this invalidates the current selection. */
virtual void setText( const wchar_t* pText );
virtual void setToolTipText(const wchar_t* text);
/* Returns the index of the selected item. */
s32 getSelected() const;
/* Returns the text of the selected item. */
const wchar_t* getSelectedText() const;
const wchar_t* getItemText( u32 pIndex ) const;
void setItemText( u32 pIndex, const wchar_t* pText );
void setItemEnabled( u32 pIndex, bool pEnable );
bool isItemEnabled( u32 pIndex ) const;
u32 getItemCount() const;
void removeItem( u32 pIndex );
void removeAllItems();
void addItem( const wchar_t* pText, bool pEnabled=true );
virtual void updateAbsolutePosition() _IRR_OVERRIDE_;
virtual bool OnEvent( const SEvent& event ) _IRR_OVERRIDE_;
virtual void draw() _IRR_OVERRIDE_;
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "dropdownSelector"; }
virtual void serializeAttributes( io::IAttributes* out, io::SAttributeReadWriteOptions* options ) const _IRR_OVERRIDE_;
virtual void deserializeAttributes( io::IAttributes* in, io::SAttributeReadWriteOptions* options ) _IRR_OVERRIDE_;
protected:
void sendGUIEvent( EGUI_EVENT_TYPE pEventType, IGUIElement* pElement=0 );
};
}}
#endif // #ifndef GUI_DROPDOWN_SELECTOR_H

View File

@ -0,0 +1,79 @@
// Copyright 2018 Nicolaus Anderson
#ifndef GUI_DROPDOWN_SELECTOR_FACTORY_H
#define GUI_DROPDOWN_SELECTOR_FACTORY_H
#include "GUIDropdownSelector.h"
#include <IGUIElementFactory.h>
namespace irr {
namespace gui {
class IGUIEnvironment;
class GUIDropdownSelectorFactory : public IGUIElementFactory {
IGUIEnvironment* Environment;
const core::stringc Label;
public:
GUIDropdownSelectorFactory( IGUIEnvironment* environment )
: Environment(environment)
, Label("dropdown")
{}
IGUIElement* addGUIElement(EGUI_ELEMENT_TYPE type, IGUIElement* parent) {
if ( type != EGUIET_ELEMENT )
return 0;
IGUIElement* e = new GUIDropdownSelector(
Environment,
parent? parent : Environment->getRootGUIElement(),
core::recti(0,0,100,100), -1);
e->drop();
return e;
}
IGUIElement* addGUIElement(const c8* typeName, IGUIElement* parent) {
if ( Label != typeName )
return 0;
IGUIElement* e = new GUIDropdownSelector(
Environment,
parent? parent : Environment->getRootGUIElement(),
core::recti(0,0,100,100), -1);
e->drop();
return e;
}
s32 getCreatableGUIElementTypeCount() const {
return 1;
}
EGUI_ELEMENT_TYPE getCreateableGUIElementType(s32 idx) const {
return EGUIET_ELEMENT;
}
const c8* getCreateableGUIElementTypeName(s32 idx) const {
if ( idx == 0 )
return Label.c_str();
return 0;
}
const c8* getCreateableGUIElementTypeName(EGUI_ELEMENT_TYPE type) const {
if ( type == EGUIET_ELEMENT )
return Label.c_str();
return 0;
}
EGUI_ELEMENT_TYPE getTypeFromName(const c8* name) const {
return EGUIET_ELEMENT;
}
};
}}
#endif

View File

@ -0,0 +1,291 @@
// (c) 2015 Nicolaus Anderson
#ifndef GUI_DUAL_SECTION_CPP
#define GUI_DUAL_SECTION_CPP
#include "GUIDualSection.h"
#include <irrMath.h>
#include <IGUISkin.h>
#include <IGUIEnvironment.h>
namespace irr {
namespace gui {
using core::recti;
GUIDualSection::GUIDualSection( bool pVertical, f32 pShift, IGUIEnvironment* pEnvironment, IGUIElement* pParent, recti pRect, s32 id )
: IGUIElement( EGUIET_ELEMENT, pEnvironment, pParent, id, pRect )
, sectionTopLeft(0)
, sectionBottomRight(0)
, vertical( pVertical )
, dragBarSize(10)
, currShift(pShift) // Normal is 0.5f
, dragBarRect()
, lastMousePos()
, currMousePos()
, dragging(false)
{
sectionTopLeft = new IGUIElement( EGUIET_ELEMENT, Environment, this, -1, pRect );
sectionBottomRight = new IGUIElement( EGUIET_ELEMENT, Environment, this, -1, pRect );
sectionTopLeft->setSubElement(true);
sectionBottomRight->setSubElement(true);
// set left, right, top, bottom alignments
setVerticalNoUpdateAbs( vertical );
cramSections();
}
GUIDualSection::~GUIDualSection()
{
sectionTopLeft->drop();
sectionBottomRight->drop();
}
IGUIElement* GUIDualSection::getSectionTopLeft()
{
return sectionTopLeft;
}
IGUIElement* GUIDualSection::getSectionBottomRight()
{
return sectionBottomRight;
}
void GUIDualSection::addChild( IGUIElement* child)
{
if ( ! sectionTopLeft && ! sectionBottomRight )
IGUIElement::addChild(child);
}
void GUIDualSection::removeChild( IGUIElement* child )
{
if ( ! sectionTopLeft && ! sectionBottomRight )
IGUIElement::removeChild(child);
}
void GUIDualSection::updateAbsolutePosition()
{
IGUIElement::updateAbsolutePosition();
updateDragBar();
}
bool GUIDualSection::OnEvent( const SEvent& event )
{
if ( !isVisible() || !isEnabled() )
return false;
s32 topLeftGap,
bottomRightGap,
deltaPos;
switch( event.EventType )
{
case EET_MOUSE_INPUT_EVENT:
// Don't forget to account for events where the sections reach or are at 0 in width/height
// I'd also like to show arrows when the mouse is over the drag bar
currMousePos.set(event.MouseInput.X, event.MouseInput.Y);
switch( event.MouseInput.Event )
{
case EMIE_LMOUSE_PRESSED_DOWN:
if ( dragBarRect.isPointInside( currMousePos ) )
{
lastMousePos = currMousePos;
dragging = true;
return true;
}
break;
case EMIE_LMOUSE_LEFT_UP:
if ( dragging )
{
recti topLeftRect = sectionTopLeft->getRelativePosition();
recti bottomRightRect = sectionBottomRight->getRelativePosition();
if ( vertical )
{
topLeftGap = topLeftRect.getHeight();
bottomRightGap = bottomRightRect.getHeight();
deltaPos = currMousePos.Y - lastMousePos.Y;
//deltaPos = core::clamp(deltaPos, -topLeftGap, bottomRightGap);
topLeftRect.LowerRightCorner.Y += deltaPos;
bottomRightRect.UpperLeftCorner.Y += deltaPos;
currShift += (f32)deltaPos / (f32)RelativeRect.getHeight();
} else {
topLeftGap = topLeftRect.getWidth();
bottomRightGap = bottomRightRect.getWidth();
deltaPos = currMousePos.X - lastMousePos.X;
//deltaPos = core::clamp(deltaPos, -topLeftGap, bottomRightGap);
topLeftRect.LowerRightCorner.X += deltaPos;
bottomRightRect.UpperLeftCorner.X += deltaPos;
currShift += (f32)deltaPos / (f32)RelativeRect.getWidth();
}
//if ( deltaPos != 0 )
{
sectionTopLeft->setRelativePosition( topLeftRect );
sectionTopLeft->updateAbsolutePosition();
sectionBottomRight->setRelativePosition( bottomRightRect );
sectionBottomRight->updateAbsolutePosition();
updateDragBar();
}
dragging = false;
return true;
}
break;
default: break;
}
break;
case EET_GUI_EVENT:
if ( event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST
&& event.GUIEvent.Caller == this )
{
dragging = false;
}
break;
default: break;
}
return IGUIElement::OnEvent(event);
}
void GUIDualSection::draw()
{
IGUIElement::draw();
Environment->getSkin()->draw3DButtonPaneStandard( this, dragBarRect, &AbsoluteClippingRect );
if ( !dragging ) return;
// Draw drag bar potential position
recti dbpp;
s32 w = AbsoluteRect.getWidth();
s32 h = AbsoluteRect.getHeight();
s32 left; // top/left - near bound
s32 right; // bottom/right - far bound
s32 halfDragBarSize = dragBarSize / 2;
core::vector2di ulc = AbsoluteRect.UpperLeftCorner;
if ( vertical )
{
left = core::clamp( currMousePos.Y - halfDragBarSize, 0, h );
right = core::clamp( currMousePos.Y + halfDragBarSize, 0, h );
dbpp = recti( ulc.X, left, ulc.X + w, right );
} else {
left = core::clamp( currMousePos.X - halfDragBarSize, 0, w );
right = core::clamp( currMousePos.X + halfDragBarSize, 0, w );
dbpp = recti( left, ulc.Y, right, ulc.Y + h );
}
Environment->getSkin()->draw2DRectangle( this, video::SColor(0x88888888), dbpp, &AbsoluteClippingRect );
}
void GUIDualSection::setVertical( bool yes ) {
setVerticalNoUpdateAbs(yes);
updateAbsolutePosition();
}
void GUIDualSection::setShiftPercentage( f32 pShift )
{
currShift = pShift;
cramSections();
}
void GUIDualSection::cramSections()
{
s32 open = 0; // open/available area
s32 w = RelativeRect.getWidth();
s32 h = RelativeRect.getHeight();
// Calculate sizes of the sections
if ( vertical )
{
open = h - dragBarSize;
} else {
open = w - dragBarSize;
}
f32 topLeftPerc = currShift * (f32)open;
f32 bottomRightPerc = (f32)open - topLeftPerc;
recti topLeftRect; // GUI area devoted to the top/left section
recti bottomRightRect; // GUI area devoted to the bottom/right section
if ( vertical )
{
topLeftRect = recti(0, 0, w, s32(h*topLeftPerc) );
bottomRightRect = recti(0, s32(h*bottomRightPerc + dragBarSize), w, h );
dragBarRect = recti( 0, topLeftRect.LowerRightCorner.Y, w, bottomRightRect.UpperLeftCorner.Y );
} else {
topLeftRect = recti(0, 0, s32(w*topLeftPerc), h );
bottomRightRect = recti(s32(w*bottomRightPerc + dragBarSize), w, 0, h );
dragBarRect = recti( topLeftRect.LowerRightCorner.X, 0, bottomRightRect.UpperLeftCorner.X, h );
}
sectionTopLeft->setRelativePosition( topLeftRect );
sectionBottomRight->setRelativePosition( bottomRightRect );
sectionTopLeft->updateAbsolutePosition();
sectionBottomRight->updateAbsolutePosition();
// Put drag rectangle in absolute coordinate space
dragBarRect += AbsoluteRect.UpperLeftCorner;
}
void GUIDualSection::updateDragBar()
{
s32 halfDragBarSize = dragBarSize / 2;
s32 pos, w, h;
w = RelativeRect.getWidth();
h = RelativeRect.getHeight();
if ( vertical )
{
pos = (s32)((f32)h * currShift);
dragBarRect = recti( 0, pos - halfDragBarSize, w, pos + halfDragBarSize );
} else {
pos = (s32)((f32)w * currShift);
dragBarRect = recti( pos - halfDragBarSize, 0, pos + halfDragBarSize, h );
}
dragBarRect += AbsoluteRect.UpperLeftCorner;
}
void
GUIDualSection::setVerticalNoUpdateAbs( bool yes )
{
vertical = yes;
// set left, right, top, bottom alignments
if ( vertical ) // one section above the other
{
sectionTopLeft->setAlignment( EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT );
sectionBottomRight->setAlignment( EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT );
} else { // sections side by side
sectionTopLeft->setAlignment( EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT );
sectionBottomRight->setAlignment( EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT );
}
}
void
GUIDualSection::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
IGUIElement::serializeAttributes(out, options);
out->addBool( "IsVertical", vertical );
out->addInt( "DragBarSize", dragBarSize );
out->addFloat( "Shift", currShift );
}
void
GUIDualSection::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
IGUIElement::deserializeAttributes(in, options);
setVertical( in->getAttributeAsBool( "IsVertical", vertical ) );
dragBarSize = in->getAttributeAsInt( "DragBarSize", dragBarSize );
setShiftPercentage( in->getAttributeAsFloat( "Shift", currShift ) );
}
}}
#endif // #ifndef GUI_DUAL_SECTION_CPP

View File

@ -0,0 +1,74 @@
// (c) 2015 Nicolaus Anderson
#ifndef GUI_DUAL_SECTION_H
#define GUI_DUAL_SECTION_H
#include <IGUIElement.h>
namespace irr {
namespace gui {
//! Class Dual Section
/* Creates and controls two child GUI elements side by side and forced to share the same space.
It also creates a draggable bar that allows the user to resize these elements.
Add children to these child GUI elements via getSectionTopLeft() and getSectionBottomRight().
Other children can be added to this element which are not controlled. Use the normal addChild method. */
class GUIDualSection : public IGUIElement
{
IGUIElement* sectionTopLeft;
IGUIElement* sectionBottomRight;
bool vertical;
s32 dragBarSize; // Size of the drag bar (currently, cannot be changed)
f32 currShift; // Current % each section shares of the space in the parent GUI element
core::rect<s32> dragBarRect;
core::vector2d<s32> lastMousePos;
core::vector2d<s32> currMousePos;
bool dragging;
public:
//! Constructor
/* \param pVertical - Indicates if the sections should be split vertically, one on top and
one on the bottom. Otherwise, they will be split horizontally.
\param pShift - The percentage of the available GUI space occupied by the top/left section.
*/
GUIDualSection( bool pVertical, f32 pShift, IGUIEnvironment* pEnvironment, IGUIElement* pParent, core::rect<s32> pRect, s32 id=-1 );
~GUIDualSection();
// Grab these to add children to the controlled elements
IGUIElement* getSectionTopLeft();
IGUIElement* getSectionBottomRight();
// Prevent re-adding controlled children
virtual void addChild( IGUIElement* child);
// Prevent removal of controlled children
virtual void removeChild( IGUIElement* child );
virtual void updateAbsolutePosition();
virtual bool OnEvent( const SEvent& event );
virtual void draw();
void setVertical( bool yes );
void setShiftPercentage( f32 pShift );
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "dualSection"; }
virtual void serializeAttributes(io::IAttributes*, io::SAttributeReadWriteOptions*) const;
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
protected:
// Fits the elements into the window
// Cannot be in updateAbsolutePosition() because it is needed in the constructor
void cramSections(); // only used for strict alignment
void updateDragBar();
void setVerticalNoUpdateAbs( bool );
};
}}
#endif // #ifndef GUI_DUAL_SECTION_H

View File

@ -0,0 +1,432 @@
// (c) 2015-2019 Nicolaus Anderson
#ifndef GUI_FILE_SELECT_PANEL_CPP
#define GUI_MATERIAL_PANEL_CPP
#include "GUIFileSelectPanel.h"
#include <irrArray.h>
#include <IGUIEnvironment.h>
#include <IFileSystem.h>
#include <IFileList.h>
#include <locale.h>
//#include <os.h> // needed for locale
#include <IGUIButton.h>
#include <IGUIListBox.h>
#include <IGUIEditBox.h>
namespace irr {
namespace gui {
using core::string;
using core::vector2di;
using core::dimension2di;
GUIFileSelectPanel::GUIFileSelectPanel(
IGUIEnvironment* pEnvironment,
IGUIElement* pParent,
recti pRect,
io::path pStartDirectory,
s32 id )
: IGUIElement( EGUIET_ELEMENT, pEnvironment, pParent, id, pRect )
, fileSystem(0)
, fileList(0)
, filesIndex()
, selectButton(0)
, cancelButton(0)
, fileListBox(0)
, fileNameEditBox(0)
, isFileSelectedFromList(false)
, lastFileSelectPanelEvent(EGFSPE_NONE)
, notifyWhenEditBoxChanges(false)
, restoreDirWhenDone(true)
, restoreDirWhenCancelled(true)
, initialWorkingDir()
, currentWorkingDir()
, drawBack(true)
{
fileSystem = Environment->getFileSystem();
fileSystem->grab();
recti selectButtonRect( vector2di(pRect.getWidth()-130, pRect.getHeight()-25), dimension2di(60,20) );
selectButton = Environment->addButton( selectButtonRect, this, -1, L"Select", L"Confirm file name" );
selectButton->setAlignment( EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT );
selectButton->setSubElement(true);
selectButton->grab();
recti cancelButtonRect( vector2di(pRect.getWidth()-65, pRect.getHeight()-25), dimension2di(60,20) );
cancelButton = Environment->addButton( cancelButtonRect, this, -1, L"Cancel" );
cancelButton->setAlignment( EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT );
cancelButton->setSubElement(true);
cancelButton->grab();
recti fileListRect( 5, 5, pRect.getWidth()-5, pRect.getHeight()-55 );
fileListBox = Environment->addListBox( fileListRect, this, -1, true );
fileListBox->setAlignment( EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT );
fileListBox->setSubElement(true);
fileListBox->grab();
recti fileNameEditRect( 5, pRect.getHeight()-50, pRect.getWidth()-5, pRect.getHeight()-30 );
fileNameEditBox = Environment->addEditBox( L"", fileNameEditRect, true, this, -1 );
fileNameEditBox->setAlignment( EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT );
fileNameEditBox->setSubElement(true);
fileNameEditBox->grab();
initialWorkingDir = fileSystem->getAbsolutePath( fileSystem->getWorkingDirectory() );
if ( pStartDirectory.size() )
{
fileSystem->changeWorkingDirectoryTo( pStartDirectory );
currentWorkingDir = pStartDirectory;
} else {
currentWorkingDir = initialWorkingDir;
}
fillFileList();
}
GUIFileSelectPanel::~GUIFileSelectPanel()
{
//if ( restoreDirWhenDone )
// fileSystem->changeWorkingDirectoryTo( initialWorkingDir );
if ( selectButton )
selectButton->drop();
if ( cancelButton )
cancelButton->drop();
if ( fileListBox )
fileListBox->drop();
if ( fileNameEditBox )
fileNameEditBox->drop();
fileSystem->drop();
}
IGUIButton* GUIFileSelectPanel::getSelectButton()
{
return selectButton;
}
IGUIButton* GUIFileSelectPanel::getCancelButton()
{
return cancelButton;
}
bool GUIFileSelectPanel::OnEvent( const SEvent& event )
{
if ( event.EventType != EET_GUI_EVENT )
return false;
/*
How this should work:
Typing in an edit-box filters the list to show only matches unless
the editbox value is "", in which case, everything is shown.
The file selected is set to the file name.
isSelectedFileReal() indicates if the selected file is taken from the list.
*/
/*
DO NOT RESTORE THE DIRECTORY AFTER SELECTION.
It doesn't make sense to restore the directory before the file path has been obtained by the user.
EDIT:
I can change this if I use getFullFileName() from the fileList, which saves the directory.
*/
switch ( event.GUIEvent.EventType )
{
case EGET_BUTTON_CLICKED:
if ( event.GUIEvent.Caller == selectButton )
{
lastFileSelectPanelEvent = EGFSPE_FILE_CONFIRMED;
sendGUIEvent( EGET_FILE_SELECTED );
if ( restoreDirWhenDone )
fileSystem->changeWorkingDirectoryTo(initialWorkingDir);
return true;
}
else if ( event.GUIEvent.Caller == cancelButton )
{
lastFileSelectPanelEvent = EGFSPE_CANCEL;
sendGUIEvent( EGET_FILE_CHOOSE_DIALOG_CANCELLED );
if ( restoreDirWhenCancelled )
fileSystem->changeWorkingDirectoryTo(initialWorkingDir);
return true;
}
break;
case EGET_EDITBOX_CHANGED:
if ( event.GUIEvent.Caller == fileNameEditBox )
{
isFileSelectedFromList = false;
fillFileList();
if ( notifyWhenEditBoxChanges )
sendGUIEvent( EGET_EDITBOX_CHANGED, fileNameEditBox );
return true;
}
break;
case EGET_EDITBOX_ENTER: // another means of selection
if ( event.GUIEvent.Caller == fileNameEditBox )
{
// confirm file selection
lastFileSelectPanelEvent = EGFSPE_FILE_CONFIRMED;
//sendGUIEvent( EGET_EDITBOX_ENTER, fileNameEditBox ); // Doesn't allow file_selected filtering in parent OnEvent
sendGUIEvent( EGET_FILE_SELECTED );
if ( restoreDirWhenDone )
fileSystem->changeWorkingDirectoryTo(initialWorkingDir);
return true;
}
break;
case EGET_LISTBOX_CHANGED:
if ( event.GUIEvent.Caller == fileListBox )
{
isFileSelectedFromList = true;
lastFileSelectPanelEvent = EGFSPE_REAL_FILE_SELECTED;
//sendGUIEvent( EGET_LISTBOX_CHANGED, fileListBox ); // Doesn't allow file_selected filtering in parent OnEvent
sendGUIEvent( EGET_FILE_SELECTED );
return true;
}
break;
case EGET_LISTBOX_SELECTED_AGAIN:
if ( event.GUIEvent.Caller == fileListBox )
{
// confirm file selection
lastFileSelectPanelEvent = EGFSPE_FILE_CONFIRMED;
if ( isSelectedFileReal() )
{
//sendGUIEvent( EGET_LISTBOX_SELECTED_AGAIN, fileListBox ); // Doesn't allow file_selected filtering in parent OnEvent
sendGUIEvent( EGET_FILE_SELECTED );
if ( restoreDirWhenDone )
fileSystem->changeWorkingDirectoryTo(initialWorkingDir);
return true;
} else {
// Selected is real (since it's in the list), but it is a directory
openSelectedDirectory();
}
}
break;
default: break;
}
return false;
}
EGUIFileSelectPanelEvent GUIFileSelectPanel::getLastEvent()
{
return lastFileSelectPanelEvent;
}
void GUIFileSelectPanel::sendGUIEvent( EGUI_EVENT_TYPE pEventType, IGUIElement* pElement )
{
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = pElement;
event.GUIEvent.EventType = pEventType;
if ( Parent )
Parent->OnEvent(event);
}
void GUIFileSelectPanel::setNotifyWhenEditBoxChanges(bool yes)
{
notifyWhenEditBoxChanges = yes;
}
io::path GUIFileSelectPanel::getCurrentWorkingDirectory()
{
fileSystem->flattenFilename(currentWorkingDir);
return currentWorkingDir;
}
bool GUIFileSelectPanel::isSelectedReal()
{
return isFileSelectedFromList;
}
bool GUIFileSelectPanel::isSelectedFileReal()
{
// Must be selected from list and not be a directory
if ( isFileSelectedFromList )
{
for ( u32 i=0; i < fileList->getFileCount(); i++ )
{
if ( fileList->getFileName(i) == fileListBox->getListItem( fileListBox->getSelected() ) )
{
return ! ( fileList->isDirectory(i) );
}
}
}
return false;
}
io::path GUIFileSelectPanel::getSelectedFile()
{
if ( isFileSelectedFromList )
{
return fileList->getFileName( getSelectedFileIndex() );
}
io::path filename = fileNameEditBox->getText();
fileSystem->flattenFilename( filename );
return filename;
}
io::path GUIFileSelectPanel::getSelectedFilePath()
{
if ( isFileSelectedFromList )
{
return fileList->getFullFileName( getSelectedFileIndex() );
}
return fileSystem->getAbsolutePath( getSelectedFile() );
}
io::path GUIFileSelectPanel::getSelectedFileRelativePath()
{
return fileSystem->getRelativeFilename( getSelectedFilePath(), initialWorkingDir );
}
//! Restore the working directory to the initial directory when a file is selected
void GUIFileSelectPanel::setRestoreDirectoryWhenDone(bool yes)
{
restoreDirWhenDone = yes;
}
//! Restore the working directory to the initial directory when cancelling
void GUIFileSelectPanel::setRestoreDirectoryWhenCancelled(bool yes)
{
restoreDirWhenCancelled = yes;
}
void GUIFileSelectPanel::reactivate()
{
fileSystem->changeWorkingDirectoryTo( currentWorkingDir );
}
void GUIFileSelectPanel::deactivate()
{
fileSystem->changeWorkingDirectoryTo( initialWorkingDir );
}
s32 GUIFileSelectPanel::getSelectedFileIndex()
{
return filesIndex[ fileListBox->getSelected() ];
}
void GUIFileSelectPanel::openSelectedDirectory()
{
if ( ! fileList )
return;
//const io::path entry = fileList->getFullFileName( getSelectedFileIndex() );
const io::path entry = fileList->getFileName( getSelectedFileIndex() );
if ( entry.size() > 0 )
{
fileSystem->changeWorkingDirectoryTo( entry );
currentWorkingDir = fileSystem->getWorkingDirectory();
fillFileList();
}
}
void GUIFileSelectPanel::pathToStringW(irr::core::stringw& result, const irr::io::path& p)
{
// Taken from Irrlicht trunk 5823, probably added by CuteAlien.
#ifndef _IRR_WCHAR_FILESYSTEM
char* oldLocale = setlocale(LC_CTYPE, NULL);
setlocale(LC_CTYPE,""); // multibyteToWString is affected by LC_CTYPE. Filenames seem to need the system-locale.
core::multibyteToWString(result, p);
setlocale(LC_CTYPE, oldLocale);
#else
result = p.c_str();
#endif
}
void GUIFileSelectPanel::fillFileList()
{
#if !defined(_IRR_WINDOWS_CE_PLATFORM_)
setlocale(LC_ALL,"");
#endif
if ( fileList ) {
fileList->drop();
fileList = 0;
}
fileList = fileSystem->createFileList();
if ( !fileList ) // FIXME: Should throw, but this should also never happen
return;
filesIndex.clear();
fileListBox->clear();
s32 folderIcon = Environment->getSkin()->getIcon(EGDI_DIRECTORY);
s32 fileIcon = Environment->getSkin()->getIcon(EGDI_FILE);
stringw filterText(fileNameEditBox->getText());
stringw fileNameTemp;
for ( u32 i=0; i < fileList->getFileCount(); i++ )
{
pathToStringW(fileNameTemp, fileList->getFileName(i));
if ( filterText.size() == 0
|| ( filterText.size() > 0 && fileNameTemp.subString(0,filterText.size()) == filterText )
)
{
fileListBox->addItem(
fileNameTemp.c_str(),
(fileList->isDirectory(i)?folderIcon:0)
);
filesIndex.push_back(i);
}
}
}
void GUIFileSelectPanel::draw()
{
if ( drawBack )
{
Environment->getSkin()->draw3DSunkenPane(this,
Environment->getSkin()->getColor(EGDC_3D_FACE), true, true,
AbsoluteRect, &AbsoluteClippingRect );
}
IGUIElement::draw();
}
void
GUIFileSelectPanel::serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options
){
out->addBool("RestoreStartDirectoryWhenDone", restoreDirWhenDone);
out->addBool("RestoreStartDirectoryWhenCancelled", restoreDirWhenCancelled);
#ifndef _IRR_WCHAR_FILESYSTEM
out->addString("InitialWorkingDirectory", initialWorkingDir.c_str());
#else
out->addStringW("InitialWorkingDirectory", initialWorkingDir.c_str());
#endif
out->addBool("DrawBack", drawBack);
}
void
GUIFileSelectPanel::deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options
){
restoreDirWhenDone = in->getAttributeAsBool("RestoreStartDirectoryWhenDone", restoreDirWhenDone);
restoreDirWhenCancelled = in->getAttributeAsBool("RestoreStartDirectoryWhenCancelled", restoreDirWhenCancelled);
if ( in->existsAttribute("InitialWorkingDirectory") ) {
#ifndef _IRR_WCHAR_FILESYSTEM
initialWorkingDir = in->getAttributeAsString("InitialWorkingDirectory", initialWorkingDir.c_str());
#else
initialWorkingDir = in->getAttributeAsStringW("InitialWorkingDirectory", initialWorkingDir.c_str());
#endif
}
drawBack = in->getAttributeAsBool("DrawBack", drawBack);
}
}}
#endif

View File

@ -0,0 +1,196 @@
// (c) 2015-2019 Nicolaus Anderson
#ifndef GUI_FILE_SELECT_PANEL_H
#define GUI_FILE_SELECT_PANEL_H
#include <IGUIElement.h>
namespace irr {
namespace io {
class IFileSystem;
class IFileList;
}
namespace gui {
using core::stringw;
using core::recti;
using core::array;
using io::IFileSystem;
using io::IFileList;
class IGUIButton;
class IGUIListBox;
class IGUIEditBox;
enum EGUIFileSelectPanelEvent
{
/* No action or undefined action */
EGFSPE_NONE=0,
/* File selected.
This does not mean a file has been confirmed for selection.
It only means that a file has been clicked on in the list of files.
It DOES refer to EXISTING files. */
EGFSPE_REAL_FILE_SELECTED,
/* File confirmed.
This does not mean the file exists.
It means that the "Select" button has been clicked, or the enter
button has been pressed, or that the user has double-clicked on a file.
When no real file has been selected, isSelectedReal() and isSelectedFileReal()
should return false but getSelectedFile() should return a filename.
Furthermore, getSelectedFilePath() will return getSelectedFile() with
the current directory appended to the front. */
EGFSPE_FILE_CONFIRMED,
/* Action canceled.
This is primarily intended for windows, where the cancel action indicates
the window should close.
It indicates that the "Cancel" button has been pressed. */
EGFSPE_CANCEL,
/* The number of events */
EGFSPE_COUNT
};
//! GUI File Select Panel
/*
This is a panel that can be embedded, allowing it to be used in windows or
as the opening screen of a program. It is used for file and directory selection,
but the user can also enter in a file name. To prevent selecting non-existent
files, the existence of the selected file can be checked by isSelectedFileReal().
To check for real selection (regardless of it is a directory or not), use
isSelectedReal(). These two functions can be used in tandem if one wishes to
allow for directory selection and not file selection via
(isSelectedReal() && !isSelectedFileReal())
*/
class GUIFileSelectPanel : public IGUIElement
{
protected:
IFileSystem* fileSystem;
IFileList* fileList;
array<u32> filesIndex;
IGUIButton* selectButton;
IGUIButton* cancelButton;
IGUIListBox* fileListBox;
IGUIEditBox* fileNameEditBox;
bool isFileSelectedFromList;
EGUIFileSelectPanelEvent lastFileSelectPanelEvent;
bool notifyWhenEditBoxChanges;
bool restoreDirWhenDone;
bool restoreDirWhenCancelled;
io::path initialWorkingDir;
io::path currentWorkingDir;
bool drawBack;
public:
GUIFileSelectPanel(
IGUIEnvironment* pEnvironment,
IGUIElement* pParent,
recti pRect,
io::path pStartDirectory,
s32 id=-1
);
~GUIFileSelectPanel();
//! Get panel button
IGUIButton* getSelectButton();
IGUIButton* getCancelButton();
//! On event
/* Handles events, such as from the GUI */
virtual bool OnEvent( const SEvent& event );
//! Get panel event
/* Returns the last event from the panel.
Parent GUI elements should check this when receiving events from this element. */
EGUIFileSelectPanelEvent getLastEvent();
protected:
void sendGUIEvent( EGUI_EVENT_TYPE pEventType, IGUIElement* pElement=0 );
public:
//! Notify when edit box changes
/* Sets whether this element should attempt to notify the parent
whenever the editbox changes. This can slow things down, but it allows for
the parent to perhaps update some file-related information being displayed. */
void setNotifyWhenEditBoxChanges(bool yes);
//!
io::path getCurrentWorkingDirectory();
//! Is the selected file or folder real
bool isSelectedReal();
//! Is the selected file a real file?
bool isSelectedFileReal();
//! Selected file name
io::path getSelectedFile(); // See important note below
//! Absolute path of the selected file
io::path getSelectedFilePath();
//! Relative path from initial directory
io::path getSelectedFileRelativePath();
//! Restore the working directory to the initial directory when a file is selected
void setRestoreDirectoryWhenDone(bool);
//! Restore the working directory to the initial directory when cancelling
void setRestoreDirectoryWhenCancelled(bool);
//! Activate
/* Restores this instance's current working directory. */
void reactivate();
//! Done
/* This should be called when the element is done being used but won't be deleted.
It restores the initial directory. */
void deactivate();
/* IMPORTANT NOTE:
If ever IGUIFileOpenDialog is to be inherited (unlikely),
existing function names should be available.
Hence, getFileName() and getDirectory() are not overridden here,
especially since they return const wchar_t and const io::path&
respectively.
*/
protected:
//! Returns the saved file index of the visible file
s32 getSelectedFileIndex();
//! Open selected directory
/* Attempts to open the selected directory. */
void openSelectedDirectory();
//! Fill file list
/* Fills the file list. */
void fillFileList();
//! Path conversion
/* Converts a path from multibyte to widechar. */
void pathToStringW(irr::core::stringw&, const irr::io::path&);
public:
//! Draw
virtual void draw();
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "fileSelectPanel"; }
virtual void serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options=0
);
virtual void deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options=0
);
};
}}
#endif

View File

@ -0,0 +1,206 @@
// (c) 2015 Nicolaus Anderson
#ifndef GUI_GROUPING_PANEL_CPP
#define GUI_GROUPING_PANEL_CPP
#include "GUIGroupingPanel.h"
#include <IGUIFont.h>
#include <IGUISkin.h>
#include <IGUIEnvironment.h>
#include <ITexture.h>
#include <IVideoDriver.h>
namespace irr {
namespace gui {
using video::IVideoDriver;
using video::SColor;
using core::vector2di;
GUIGroupingPanel::GUIGroupingPanel( const wchar_t* pText, IGUIEnvironment* pEnvironment, IGUIElement* pParent, const recti& pRect, s32 id )
: IGUIElement( EGUIET_ELEMENT, pEnvironment, pParent, id, pRect )
, showBorder( true )
, borderRadius( 6 )
{
textSize = pEnvironment->getSkin()->getFont()->getDimension( pText );
Text = pText;
updateImageCache();
setTabGroup(true);
}
void GUIGroupingPanel::setText(const wchar_t* text)
{
Text = text;
textSize = Environment->getSkin()->getFont()->getDimension( text );
}
void GUIGroupingPanel::setShowBorder( bool pShow )
{
showBorder = pShow;
}
void GUIGroupingPanel::setBorderEdgeRadius( f32 pRadius )
{
borderRadius = pRadius;
updateImageCache();
}
recti GUIGroupingPanel::getClientArea()
{
return recti( borderRadius, borderRadius + textSize.Height, RelativeRect.getWidth() - borderRadius, RelativeRect.getHeight() - borderRadius );
}
//void GUIGroupingPanel::updateAbsolutePosition()
//{
//}
void GUIGroupingPanel::draw()
{
IVideoDriver* vid = Environment->getVideoDriver();
IGUISkin* skin = Environment->getSkin();
SColor color = skin->getColor( EGDC_3D_LIGHT );
SColor shadowColor = skin->getColor( EGDC_3D_SHADOW );
SColor textColor = skin->getColor( EGDC_BUTTON_TEXT );
s32 textPad = ( textSize.Width > 0 ) ? 3 : 0; // Padding is only needed when there is text
// Draw border corners
vector2di textPush(0, textSize.Height/2);
recti cornerSource( ULtexture->getSize() ); // Source rectangle for the images
vid->draw2DImage( ULtexture, AbsoluteRect.UpperLeftCorner + textPush, cornerSource, &AbsoluteClippingRect, SColor(-1), true );
vector2di corner2( AbsoluteRect.getWidth() - borderRadius, 0 );
vid->draw2DImage( URtexture, corner2 + AbsoluteRect.UpperLeftCorner + textPush, cornerSource, &AbsoluteClippingRect, SColor(-1), true );
vector2di corner( 0, AbsoluteRect.getHeight() - borderRadius );
vid->draw2DImage( LLtexture, corner + AbsoluteRect.UpperLeftCorner, cornerSource, &AbsoluteClippingRect, SColor(-1), true );
corner2 += vector2di( 0, AbsoluteRect.getHeight() - borderRadius ); // Use .move() in custom Irrlicht
vid->draw2DImage( LRtexture, corner2 + AbsoluteRect.UpperLeftCorner, cornerSource, &AbsoluteClippingRect, SColor(-1), true );
// Draw border walls
// Left side
vector2di vline( AbsoluteRect.UpperLeftCorner );
vline.Y += borderRadius + (textSize.Height / 2);
vector2di vlineEnd( AbsoluteRect.UpperLeftCorner.X, AbsoluteRect.LowerRightCorner.Y - borderRadius );
vid->draw2DLine( vline, vlineEnd, color );
vline.X += 1;
vlineEnd.X += 1;
vid->draw2DLine( vline, vlineEnd, shadowColor ); // Shadow
// Top side
vector2di hline( AbsoluteRect.UpperLeftCorner );
hline += vector2di( borderRadius + textPad*2 + textSize.Width, textSize.Height / 2 ); // Use .move() in custom Irrlicht
vector2di hlineEnd( AbsoluteRect.LowerRightCorner.X - borderRadius, AbsoluteRect.UpperLeftCorner.Y + (textSize.Height / 2) );
vid->draw2DLine( hline, hlineEnd, color );
hline.Y += 1;
hlineEnd.Y += 1;
vid->draw2DLine( hline, hlineEnd, shadowColor ); // Shadow
// Right side
vline.set( AbsoluteRect.LowerRightCorner.X, AbsoluteRect.UpperLeftCorner.Y + borderRadius + (textSize.Height / 2) );
vlineEnd.set( AbsoluteRect.LowerRightCorner );
vlineEnd.Y -= borderRadius;
vid->draw2DLine( vline, vlineEnd, color );
vline.X -= 1;
vlineEnd.X -= 1;
vid->draw2DLine( vline, vlineEnd, shadowColor ); // Shadow
// Bottom side
hline.set( AbsoluteRect.UpperLeftCorner.X + borderRadius, AbsoluteRect.LowerRightCorner.Y );
hlineEnd.set( AbsoluteRect.LowerRightCorner );
hlineEnd.X -= borderRadius;
vid->draw2DLine( hline, hlineEnd, color );
hline.Y -= 1;
hlineEnd.Y -= 1;
vid->draw2DLine( hline, hlineEnd, shadowColor ); // Shadow
// Draw label text
recti labelRect( borderRadius + 3, 0, borderRadius + textPad, textSize.Height );
Environment->getSkin()->getFont()->draw( Text.c_str(), labelRect + AbsoluteRect.UpperLeftCorner, textColor, false, false, &AbsoluteClippingRect );
// Draw child elements
IGUIElement::draw();
}
void GUIGroupingPanel::updateImageCache()
{
IVideoDriver* vid = Environment->getVideoDriver();
SColor color = Environment->getSkin()->getColor( EGDC_3D_LIGHT );
SColor shadowColor = Environment->getSkin()->getColor( EGDC_3D_SHADOW );
dimension2du imageSize( borderRadius, borderRadius );
// Produces cropped circles used as end-caps / corners
ULtexture = vid->addRenderTargetTexture( imageSize, "GUI_GROUPING_PANEL_CORNER_UL" );
if ( ULtexture )
{
// Irrlicht 5104
//vid->setRenderTarget( ULtexture );
// Irrlicht 5589
vid->setRenderTarget( ULtexture, u16(irr::video::ECBF_COLOR), SColor(0,0,0,0) );
vid->draw2DPolygon( vector2di( borderRadius+1 ), borderRadius, shadowColor, 40 );
vid->draw2DPolygon( vector2di( borderRadius, borderRadius ), borderRadius, color, 40 );
}
URtexture = vid->addRenderTargetTexture( imageSize, "GUI_GROUPING_PANEL_CORNER_UR" );
if ( URtexture )
{
// Irrlicht 5104
//vid->setRenderTarget( URtexture );
// Irrlicht 5589
vid->setRenderTarget( URtexture, u16(irr::video::ECBF_COLOR), SColor(0,0,0,0) );
vid->draw2DPolygon( vector2di( -1, borderRadius+1 ), borderRadius, shadowColor, 40 );
vid->draw2DPolygon( vector2di( 0, borderRadius ), borderRadius, color, 40 );
}
LLtexture = vid->addRenderTargetTexture( imageSize, "GUI_GROUPING_PANEL_CORNER_LL" );
if ( LLtexture )
{
// Irrlicht 5104
//vid->setRenderTarget( LLtexture );
// Irrlicht 5589
vid->setRenderTarget( LLtexture, u16(irr::video::ECBF_COLOR), SColor(0,0,0,0) );
vid->draw2DPolygon( vector2di( borderRadius+1, -1 ), borderRadius, shadowColor, 40 );
vid->draw2DPolygon( vector2di( borderRadius, 0 ), borderRadius, color, 40 );
}
LRtexture = vid->addRenderTargetTexture( imageSize, "GUI_GROUPING_PANEL_CORNER_LR" );
if ( LRtexture )
{
// Irrlicht 5104
//vid->setRenderTarget( LRtexture );
// Irrlicht 5589
vid->setRenderTarget( LRtexture, u16(irr::video::ECBF_COLOR), SColor(0,0,0,0) );
vid->draw2DPolygon( vector2di( -1 ), borderRadius, shadowColor, 40 );
vid->draw2DPolygon( vector2di( 0 ), borderRadius, color, 40 );
}
vid->setRenderTarget(0); // Should restore old target
}
void
GUIGroupingPanel::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const {
IGUIElement::serializeAttributes(out, options);
out->addBool("ShowBorder", showBorder );
out->addFloat("BorderRadius", borderRadius );
}
void
GUIGroupingPanel::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) {
IGUIElement::deserializeAttributes(in, options);
// Required so that the text size can be precalculated - NO LONGER NEEDED
//setText( in->getAttributeAsString("Caption", L"") );
showBorder = in->getAttributeAsBool("ShowBorder", showBorder);
borderRadius = in->getAttributeAsFloat("BorderRadius", borderRadius);
}
}}
#endif // #ifndef GUI_GROUPING_PANEL_CPP

View File

@ -0,0 +1,73 @@
// (c) 2015 Nicolaus Anderson
#ifndef GUI_GROUPING_PANEL_H
#define GUI_GROUPING_PANEL_H
#include <IGUIElement.h>
namespace irr {
namespace video {
class ITexture;
}
namespace gui {
using core::dimension2du;
using core::recti;
using video::ITexture;
//! Class GUI Grouping Panel
/* The sole purpose of this class is to allow for easy grouping of elements, both visibly
and programmatically. */
class GUIGroupingPanel : public IGUIElement
{
dimension2du textSize;
bool showBorder;
f32 borderRadius;
ITexture* ULtexture;
ITexture* URtexture;
ITexture* LLtexture;
ITexture* LRtexture;
public:
GUIGroupingPanel( const wchar_t* pText, IGUIEnvironment* pEnvironment, IGUIElement* pParent, const recti& pRect, s32 id=-1 );
//! Set the text
/* This function both sets the text and peforms some calculations for composing the client area. */
virtual void setText(const wchar_t* text) _IRR_OVERRIDE_;
//! Set border visible
/* Sets if the border is visible. */
void setShowBorder( bool pShow );
//! Set border edge radius
/* Sets the radius of the edge border. Note, this will effect the client area.
The larger the radius, the smaller the client area will be. */
void setBorderEdgeRadius( f32 pRadius );
/* Returns the area available to the child elements. Note that, if this area is to change,
child GUI elements should be set to retain their positions relative to the walls, NOT using EGUIA_SCALE. */
recti getClientArea();
/* Updates the absolute rectangle and the client area rectangle. */
//virtual void updateAbsolutePosition();
/* Draws the border of this element. */
virtual void draw() _IRR_OVERRIDE_;
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "groupingPanel"; }
virtual void serializeAttributes(io::IAttributes*, io::SAttributeReadWriteOptions*) const _IRR_OVERRIDE_;
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_;
protected:
//! Update image cache
/* Creates images to be drawn around the border. These are the corners. */
void updateImageCache();
};
}}
#endif // #ifndef GUI_GROUPING_PANEL_H

View File

@ -0,0 +1,385 @@
// Copyright 2018 Nicolaus Anderson
#include "GUIMarkedSlider.h"
#include <irrMath.h>
#include <SColor.h>
#include <IVideoDriver.h>
#include <IGUIFont.h>
#include <IGUISkin.h>
#include <IGUIEnvironment.h>
namespace irr {
namespace gui {
GUIMarkedSlider::GUIMarkedSlider(
bool vertical,
f32 sliderSize,
core::rect<s32> rectangle,
IGUIEnvironment* environment,
IGUIElement* parent,
s32 id
)
: IGUIElement( /*EGUIET_SCROLLBAR*/ EGUIET_ELEMENT , environment, parent, id, rectangle )
, MinValue(0)
, MaxValue(100.f)
, CurrentValue(0)
, DrawFrame(0)
, DrawTicks(false)
, DrawNumbers(false)
, NumberSpacing(10.f)
, IsVertical( vertical )
, SliderRadius( sliderSize / 2 )
, SliderSelected(false)
, StartMousePos(0)
, SliderTexture(0)
{
updateImageCache();
Environment->getVideoDriver();
}
GUIMarkedSlider::~GUIMarkedSlider()
{
}
bool GUIMarkedSlider::OnEvent( const SEvent& event ) {
if ( event.EventType == EET_MOUSE_INPUT_EVENT ) {
switch ( event.MouseInput.Event ) {
case EMIE_LMOUSE_PRESSED_DOWN:
if ( isInSliderArea( event.MouseInput.X, event.MouseInput.Y ) ) {
SliderSelected = true;
StartMousePos.set( event.MouseInput.X, event.MouseInput.Y );
} else {
if ( IsVertical ) {
setValue( event.MouseInput.Y - AbsoluteRect.UpperLeftCorner.Y - SliderRadius*2 );
} else {
setValue( event.MouseInput.X - AbsoluteRect.UpperLeftCorner.X - SliderRadius*2 );
}
}
return true;
case EMIE_LMOUSE_LEFT_UP:
if ( Environment->getFocus() == this ) {
SliderSelected = false;
return true;
}
break;
case EMIE_MOUSE_MOVED:
if ( SliderSelected ) {
if ( IsVertical ) {
setValue( event.MouseInput.Y - StartMousePos.Y );
} else {
setValue( event.MouseInput.X - StartMousePos.X );
}
return true;
}
break;
default: break;
}
}
return false;
}
void GUIMarkedSlider::setMinValue( f32 value ) {
MinValue = value;
if ( MinValue > MaxValue )
MaxValue = MinValue;
}
f32 GUIMarkedSlider::getMinValue() {
return MinValue;
}
void GUIMarkedSlider::setMaxValue( f32 value ) {
MaxValue = value;
if ( MaxValue < MinValue )
MinValue = MaxValue;
}
f32 GUIMarkedSlider::getMaxValue() {
return MaxValue;
}
void GUIMarkedSlider::setValue( f32 value ) {
// Odd as it is, to save a headache in drawing, we simply treat the CurrentValue
// as the negative of whatever the user wants
CurrentValue = core::clamp( MaxValue - value, MinValue, MaxValue );
}
f32 GUIMarkedSlider::getValue() {
// Odd as it is, to save a headache in drawing, we simply treat the CurrentValue
// as the negative of whatever the user wants
return -CurrentValue;
}
void GUIMarkedSlider::setDrawFrame( bool yes ) {
DrawFrame = yes;
}
void GUIMarkedSlider::setDrawTicks( bool yes ) {
DrawTicks = yes;
}
void GUIMarkedSlider::setDrawNumbers( bool yes ) {
DrawNumbers = yes;
}
void GUIMarkedSlider::setNumberSpacing( f32 distance ) {
NumberSpacing = distance;
}
void GUIMarkedSlider::setSliderSize( f32 sliderSize ) {
SliderRadius = sliderSize / 2;
updateImageCache();
}
bool GUIMarkedSlider::isInSliderArea( s32 x, s32 y ) {
// Create a rectangle formed by the upper left corner of the absolute position of this element
// and having a size that is the same as the slider radius times 2
core::recti r(
AbsoluteRect.UpperLeftCorner,
core::dimension2du(SliderRadius*2,SliderRadius*2)
);
return r.isPointInside( core::vector2di(x,y) );
}
void GUIMarkedSlider::updateImageCache() {
video::IVideoDriver* vid = Environment->getVideoDriver();
video::SColor lightColor = Environment->getSkin()->getColor( EGDC_3D_LIGHT );
video::SColor shadowColor = Environment->getSkin()->getColor( EGDC_3D_SHADOW );
video::SColor textColor = Environment->getSkin()->getColor( EGDC_BUTTON_TEXT );
core::dimension2du imageSize( (u32)SliderRadius * 2, (u32)SliderRadius * 2 );
core::vector2di sliderSpot( (s32)SliderRadius );
if ( ! SliderTexture )
SliderTexture = vid->addRenderTargetTexture( imageSize, "GUI_MARKED_SLIDER_TEXTURE" );
if ( SliderTexture ) {
vid->setRenderTarget( SliderTexture );
vid->draw2DPolygon( sliderSpot, (s32)SliderRadius, shadowColor, 40 );
vid->draw2DPolygon( core::vector2di( (s32)SliderRadius - 1 ), (s32)SliderRadius, lightColor, 40 );
vid->draw2DPolygon( core::vector2di( (s32)SliderRadius - 2 ), (s32)SliderRadius, shadowColor, 40 );
sliderSpot.Y = 3; // Avoid drawing over the other bands
vid->draw2DLine( sliderSpot, core::vector2di(sliderSpot.X, (s32)imageSize.Height - 3), textColor );
}
vid->setRenderTarget(0);
}
void GUIMarkedSlider::draw() {
if ( ! SliderTexture ) {
// ERROR, so just draw children
IGUIElement::draw();
return;
}
// Note to self:
// It might be faster to precalculate components to be drawn to the screen and then
// go through a list of them and use a switch to decide how to draw them.
video::IVideoDriver* vid = Environment->getVideoDriver();
IGUISkin* skin = Environment->getSkin();
video::SColor lightColor = skin->getColor( EGDC_3D_LIGHT );
video::SColor shadowColor = skin->getColor( EGDC_3D_SHADOW );
video::SColor textColor = skin->getColor( EGDC_BUTTON_TEXT );
video::SColor faceColor = skin->getColor( EGDC_3D_FACE );
s32 halfTextHeight = skin->getFont()->getKerningHeight() / 2;
core::vector2di drawStart, drawEnd, drawSave, drawSave2; // drawSaves are temporary storage variables
s32 halfElemWidth = AbsoluteRect.getWidth() / 2;
s32 halfElemHeight = AbsoluteRect.getHeight() / 2;
core::recti SliderTextureRect( SliderTexture->getSize() );
s32 sSliderRadius = (s32)SliderRadius;
f32 drawValue;
f32 drawSpacing;
f32 lineIndex;
core::recti numberTextRect;
if ( DrawFrame ) {
skin->draw3DSunkenPane(this, faceColor, false, true, AbsoluteRect, &AbsoluteClippingRect);
}
if ( IsVertical ) {
drawSpacing = NumberSpacing * ((halfElemWidth - SliderRadius) * 2) / (MaxValue - MinValue + 0.00001);
drawStart.X = AbsoluteRect.UpperLeftCorner.X + halfElemWidth;
drawStart.Y = AbsoluteRect.UpperLeftCorner.Y + sSliderRadius;
drawEnd.X = AbsoluteRect.UpperLeftCorner.X + halfElemWidth;
drawEnd.Y = AbsoluteRect.LowerRightCorner.Y - sSliderRadius;
vid->draw2DLine( drawStart, drawEnd, lightColor );
drawStart.X += 1;
drawEnd.X += 1;
vid->draw2DLine( drawStart, drawEnd, shadowColor );
if ( DrawTicks ) {
// Ticks on the ends
drawStart.X -= sSliderRadius + 1;
drawEnd.X += sSliderRadius + 1;
drawSave.Y = drawEnd.Y;
drawEnd.Y = drawStart.Y;
vid->draw2DLine( drawStart, drawEnd, lightColor );
drawStart.Y = drawSave.Y;
drawEnd.Y = drawSave.Y;
vid->draw2DLine( drawStart, drawEnd, lightColor );
// Draw in reverse-numeric order (since we're always working upside-down)
drawSave.X = drawStart.X;
drawSave2.X = drawEnd.X;
drawSave.Y = drawSave2.Y = drawEnd.Y - (s32)drawSpacing;
for ( lineIndex = 0; drawSave.Y > drawStart.Y; ++lineIndex ) {
vid->draw2DLine( drawSave, drawSave2, textColor );
drawSave.Y = drawSave2.Y = drawEnd.Y - (s32)(drawSpacing * lineIndex);
}
}
if ( DrawNumbers ) {
// Draw in bottom->up (since we're always working upside-down)
drawValue = MinValue;
drawStart.Y = AbsoluteRect.UpperLeftCorner.Y + sSliderRadius;
drawEnd.Y = AbsoluteRect.LowerRightCorner.Y - sSliderRadius;
drawSave.X = AbsoluteRect.LowerRightCorner.X - halfElemWidth + 1; // Numbers go to the right of the line
drawSave.Y = drawEnd.Y - halfTextHeight;
drawSave2.X = AbsoluteRect.LowerRightCorner.X;
drawSave2.Y = drawEnd.Y + halfTextHeight;
numberTextRect = core::recti( drawSave, drawSave2 );
for ( lineIndex = 0; drawSave.Y > drawStart.Y; ++lineIndex ) {
const core::stringw numberText( drawValue );
skin->getFont()->draw( numberText.c_str(), numberTextRect, textColor, false, false, &AbsoluteClippingRect );
drawValue - NumberSpacing;
numberTextRect = core::recti( drawSave, drawSave2 );
numberTextRect += core::vector2di(0, - (s32)( drawSpacing * lineIndex ) );
}
// Draw the last number separately so that it's correctly lined up
drawSave.Y = drawStart.Y - halfTextHeight;
drawSave2.Y = drawStart.Y + halfTextHeight;
numberTextRect = core::recti(drawSave, drawSave2);
const core::stringw numberTextFinal( MinValue );
skin->getFont()->draw( numberTextFinal.c_str(), numberTextRect, textColor, false, false, &AbsoluteClippingRect );
}
// Draw the slider marker last
drawStart.set( halfElemWidth - sSliderRadius, CurrentValue - sSliderRadius );
vid->draw2DImage( SliderTexture, AbsoluteRect.UpperLeftCorner + drawStart, SliderTextureRect, &AbsoluteClippingRect, video::SColor(-1), true );
} else {
// Horizontal Slider
drawSpacing = NumberSpacing * ((halfElemHeight - SliderRadius) * 2) / (MaxValue - MinValue + 0.00001);
drawStart.X = AbsoluteRect.UpperLeftCorner.X + sSliderRadius;
drawStart.Y = AbsoluteRect.UpperLeftCorner.Y + halfElemHeight;
drawEnd.X = AbsoluteRect.LowerRightCorner.X - sSliderRadius;
drawEnd.Y = AbsoluteRect.UpperLeftCorner.Y + halfElemHeight;
vid->draw2DLine( drawStart, drawEnd, lightColor );
drawStart.Y += 1;
drawEnd.Y += 1;
vid->draw2DLine( drawStart, drawEnd, shadowColor );
if ( DrawTicks ) {
// Ticks on the ends
drawStart.Y -= sSliderRadius + 1;
drawEnd.Y += sSliderRadius + 1;
drawSave.X = drawEnd.X;
drawEnd.X = drawStart.X;
vid->draw2DLine( drawStart, drawEnd, lightColor );
drawStart.X = drawSave.X;
drawEnd.X = drawSave.X;
vid->draw2DLine( drawStart, drawEnd, lightColor );
// Draw in reverse-numeric order (since we're always working upside-down)
drawSave.Y = drawStart.Y;
drawSave2.Y = drawEnd.Y;
drawSave.X = drawSave2.X = drawEnd.X - drawSpacing;
for ( lineIndex = 0; drawSave.X > drawStart.X; ++lineIndex ) {
vid->draw2DLine( drawSave, drawSave2, lightColor );
drawSave.X = drawSave2.X = drawEnd.X - drawSpacing * lineIndex;
}
}
if ( DrawNumbers ) {
// Draw in left->right
drawValue = MinValue;
drawEnd.X = AbsoluteRect.LowerRightCorner.X - sSliderRadius;
drawSave.X = AbsoluteRect.UpperLeftCorner.Y + sSliderRadius;
drawSave.Y = AbsoluteRect.LowerRightCorner.Y + halfElemHeight + sSliderRadius * 2 + 1;
drawSave2.X = drawStart.X + drawSpacing;
drawSave2.Y = drawSave.Y + halfTextHeight * 2; // We'll let the compiler optimize *2 to <<2
numberTextRect = core::recti( drawSave, drawSave2 );
for ( lineIndex = 0; drawSave.X < drawEnd.X; ++lineIndex ) {
const core::stringw numberText( drawValue );
skin->getFont()->draw( numberText.c_str(), numberTextRect, textColor, false, false, &AbsoluteClippingRect );
drawValue + NumberSpacing;
numberTextRect = core::recti( drawSave, drawSave2 );
numberTextRect += core::vector2di( (s32)( drawSpacing * lineIndex ), 0 );
}
// Draw the last number separately so that it's correctly lined up
drawSave.X = drawEnd.X;
drawSave2.X = AbsoluteRect.LowerRightCorner.X;
numberTextRect = core::recti(drawSave, drawSave2);
const core::stringw numberTextFinal( MinValue );
skin->getFont()->draw( numberTextFinal.c_str(), numberTextRect, textColor, false, false, &AbsoluteClippingRect );
}
// Draw the slider marker last
drawStart.set( CurrentValue - sSliderRadius, halfElemHeight );
vid->draw2DImage( SliderTexture, AbsoluteRect.UpperLeftCorner + drawStart, SliderTextureRect, &AbsoluteClippingRect, video::SColor(-1), true );
}
IGUIElement::draw(); // Children
}
void GUIMarkedSlider::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
IGUIElement::serializeAttributes(out,options);
f32 MinValue;
f32 MaxValue;
f32 CurrentValue;
bool DrawFrame;
bool DrawTicks;
bool DrawNumbers;
f32 NumberSpacing;
bool IsVertical;
f32 SliderRadius;
out->addFloat("MinValue", MinValue);
out->addFloat("MaxValue", MaxValue);
out->addFloat("CurrentValue", CurrentValue);
out->addBool("DrawFrame", DrawFrame);
out->addBool("DrawTicks", DrawTicks);
out->addBool("DrawNumbers", DrawNumbers);
out->addFloat("NumberSpacing", NumberSpacing);
out->addBool("IsVertical", IsVertical);
out->addFloat("SliderRadius", SliderRadius);
}
void GUIMarkedSlider::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
IGUIElement::deserializeAttributes(in, options);
MinValue = in->getAttributeAsFloat("MinValue", MinValue);
MaxValue = in->getAttributeAsFloat("MaxValue", MaxValue);
CurrentValue = in->getAttributeAsFloat("CurrentValue", CurrentValue);
DrawFrame = in->getAttributeAsBool("DrawFrame", DrawFrame);
DrawTicks = in->getAttributeAsBool("DrawTicks", DrawTicks);
DrawNumbers = in->getAttributeAsBool("DrawNumbers", DrawNumbers);
NumberSpacing = in->getAttributeAsFloat("NumberSpacing", NumberSpacing);
IsVertical = in->getAttributeAsBool("IsVertical", IsVertical);
f32 sliderRadius = in->getAttributeAsFloat("SliderRadius", SliderRadius);
if ( sliderRadius != SliderRadius )
setSliderSize(SliderRadius*2); // Updates image cache
}
}}

View File

@ -0,0 +1,68 @@
// Copyright 2018 Nicolaus Anderson
#include "IGUIElement.h"
#ifndef __GUI_MARKED_SLIDER_H__
#define __GUI_MARKED_SLIDER_H__
namespace irr {
namespace gui {
//! Marked Slider class
/*
Draws a long line (the number line) with marked values (below it if the line is vertical or to the right of it if the line is horizontal).
It draws value marker that marks the current value of the slider. It can have different appearances.
- A circle
- (Not yet) Two arrows pointing at a short line in between them which is perpendicular to the number line.
Greyed out when disabled.
*/
class GUIMarkedSlider : public IGUIElement {
public:
GUIMarkedSlider(bool vertical, f32 sliderSize, core::rect<s32> rectangle, IGUIEnvironment* environment, IGUIElement* parent=0, s32 id=-1 );
~GUIMarkedSlider();
virtual bool OnEvent( const SEvent& event ) _IRR_OVERRIDE_;
virtual void draw() _IRR_OVERRIDE_;
void setMinValue( f32 );
f32 getMinValue();
void setMaxValue( f32 );
f32 getMaxValue();
void setValue( f32 );
f32 getValue();
void setDrawFrame( bool );
void setDrawTicks( bool );
void setDrawNumbers( bool );
void setNumberSpacing( f32 ); // Distance between drawn numbers
void setSliderSize( f32 );
bool isInSliderArea( s32 x, s32 y );
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "markedSlider"; }
virtual void serializeAttributes(io::IAttributes*, io::SAttributeReadWriteOptions*) const _IRR_OVERRIDE_;
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_;
private:
void updateImageCache();
f32 MinValue;
f32 MaxValue;
f32 CurrentValue;
bool DrawFrame;
bool DrawTicks;
bool DrawNumbers;
f32 NumberSpacing;
bool IsVertical;
f32 SliderRadius;
bool SliderSelected;
core::vector2di StartMousePos;
video::ITexture* SliderTexture;
};
}}
#endif

View File

@ -0,0 +1,848 @@
// (c) 2014 Nicolaus Anderson
#include "GUIMaterialPanel.h"
#include <IGUIButton.h>
#include <IGUICheckBox.h>
#include <IGUIWindow.h>
#include <IGUIEditBox.h>
#include <SMaterial.h>
#include "GUIColorEditBox.h"
#include "GUIColorSample.h"
#include "GUISColorSelect.h"
#include <IMeshSceneNode.h>
#include <ISceneManager.h>
#include "scene/GUIScene.h"
#include "GUIWindow2.h"
#include "GUIFileSelectPanel.h"
namespace irr {
namespace gui {
using core::vector2di;
using core::recti;
using core::dimension2d;
using video::SMaterial;
GUIMaterialPanel::GUIMaterialPanel(
IGUIEnvironment* pEnvironment,
ISceneManager* pSceneManager,
IGUIElement* pParent,
recti pRect,
s32 id
)
: IGUIElement( EGUIET_ELEMENT, pEnvironment, pParent, id, pRect )
, material(0)
, meshMaterialScene(0)
, ambientColorEditBox(0)
, ambientPanelSample(0)
, ambientColorButton(0)
, ambientColorSelectWindow(0)
, ambientColorSelect(0)
, ambientColorSample(0)
, diffuseColorEditBox(0)
, diffusePanelSample(0)
, diffuseColorButton(0)
, diffuseColorSelectWindow(0)
, diffuseColorSelect(0)
, diffuseColorSample(0)
, emissiveColorEditBox(0)
, emissivePanelSample(0)
, emissiveColorButton(0)
, emissiveColorSelectWindow(0)
, emissiveColorSelect(0)
, emissiveColorSample(0)
, specularColorEditBox(0)
, specularPanelSample(0)
, specularColorButton(0)
, specularColorSelectWindow(0)
, specularColorSelect(0)
, specularColorSample(0)
, wireframeCheckbox(0)
, gourandShadingCheckbox(0)
, lightingCheckbox(0)
, mipmapsCheckbox(0)
, colorSelectWindowRect(0, 0, 210, 210)
, textureNameEditBox(0)
, textureSelectButton(0)
, textureRemoveButton(0)
, selectTextureWindow(0)
, selectTextureFilePanel(0)
{
// Create the user interface
setTabGroup(true);
/* When designing a mesh that must become transparent or fade,
you can use this setting: */
// EMT_TRANSPARENT_VERTEX_ALPHA
/* This setting (which applies to the material; see EMaterialTypes.h)
sets the transparency based on the vertex color alpha.
It would be useful to add a checkbox that allows the user to
select use-the-alpha-value so that the mesh can either be transparent
or solid (for faster rendering).
NOTE: When doing this, if you want to combine both vertex-alpha (to fade
the whole thing) with texture alpha, you will have to write a shader. */
s32 startY = 15; // In case the mesh scene is added
// create GUI Mesh Scene with sphere with material
//meshMaterialScene = new GUIScene( Environment, pSceneManager, this, recti() );
//materialSceneNode = meshMaterialScene->GetScene()->addSphereSceneNode();
//meshMaterialScene->SetOptimalCamDistToNode( materialSceneNode );
//updateMeshScene();
s32 boxW, boxH;
boxW = 65; boxH = 20;
recti textRect(0,startY,boxW+5,boxH+15);
recti valueRect(textRect);
valueRect += vector2di( boxW+15, 0 );
vector2di shiftY(0,boxH+5);
recti sampleRect( 0, 0, boxH, boxH );
sampleRect += vector2di( valueRect.LowerRightCorner.X + 15, valueRect.UpperLeftCorner.Y );
// ********* Ambient color
ambientColorButton = Environment->addButton(
textRect,
this, -1,
L"Ambient",
L"Open ambient color selection window" );
//ambientColorButton->setTabStop(true);
//ambientColorButton->setTabOrder(0);
ambientColorEditBox = new GUIColorEditBox( Environment, this, valueRect );
ambientColorEditBox->setTabStop(true);
ambientColorEditBox->setTabOrder(-1);
ambientPanelSample = new GUIColorSample( pEnvironment, this, sampleRect );
ambientPanelSample->setDrawBorder(true);
ambientPanelSample->showOneColor( 0xffffffff );
// ********* Diffuse color
textRect += shiftY;
diffuseColorButton = Environment->addButton(
textRect,
this, -1,
L"Diffuse",
L"Open diffuse color selection window" );
//diffuseColorButton->setTabStop(true);
//diffuseColorButton->setTabOrder(2);
valueRect += shiftY;
diffuseColorEditBox = new GUIColorEditBox( Environment, this, valueRect );
diffuseColorEditBox->setTabStop(true);
diffuseColorEditBox->setTabOrder(-1);
sampleRect += shiftY;
diffusePanelSample = new GUIColorSample( pEnvironment, this, sampleRect );
diffusePanelSample->setDrawBorder(true);
diffusePanelSample->showOneColor( 0xffffffff );
// ********* Emissive color
textRect += shiftY;
emissiveColorButton = Environment->addButton(
textRect,
this, -1,
L"Emissize",
L"Open emissive color selection window" );
//emissiveColorButton->setTabStop(true);
//emissiveColorButton->setTabOrder(4);
valueRect += shiftY;
emissiveColorEditBox = new GUIColorEditBox( Environment, this, valueRect );
emissiveColorEditBox->setTabStop(true);
emissiveColorEditBox->setTabOrder(-1);
sampleRect += shiftY;
emissivePanelSample = new GUIColorSample( pEnvironment, this, sampleRect );
emissivePanelSample->setDrawBorder(true);
emissivePanelSample->showOneColor( 0xffffffff );
// ********* Specular color
textRect += shiftY;
specularColorButton = Environment->addButton(
textRect,
this, -1,
L"Specular",
L"Open specular color selection window" );
//specularColorButton->setTabStop(true);
//specularColorButton->setTabOrder(6);
valueRect += shiftY;
specularColorEditBox = new GUIColorEditBox( Environment, this, valueRect );
specularColorEditBox->setTabStop(true);
specularColorEditBox->setTabOrder(-1);
sampleRect += shiftY;
specularPanelSample = new GUIColorSample( pEnvironment, this, sampleRect );
specularPanelSample->setDrawBorder(true);
specularPanelSample->showOneColor( 0xffffffff );
// Enlargen the text box to fit the text and checkbox
textRect.LowerRightCorner = valueRect.LowerRightCorner;
// ********* Wireframe
textRect += shiftY;
wireframeCheckbox = Environment->addCheckBox(
false, // checked?
textRect,
this, -1,
L"Wireframe" );
wireframeCheckbox->setTabStop(true);
wireframeCheckbox->setTabOrder(-1);
// ********* Gourand Shading
textRect += shiftY;
gourandShadingCheckbox = Environment->addCheckBox(
false,
textRect,
this, -1,
L"Gourand Shading" );
gourandShadingCheckbox->setTabStop(true);
gourandShadingCheckbox->setTabOrder(-1);
// ********* Lighting
textRect += shiftY;
lightingCheckbox = Environment->addCheckBox(
false,
textRect,
this, -1,
L"Lit by Lights" );
lightingCheckbox->setTabStop(true);
lightingCheckbox->setTabOrder(-1);
// ********* Mipmaps
textRect += shiftY;
mipmapsCheckbox = Environment->addCheckBox(
false,
textRect,
this, -1,
L"Use Mipmaps" );
mipmapsCheckbox->setTabStop(true);
mipmapsCheckbox->setTabOrder(-1);
// ********* Texture
textRect += shiftY + vector2di(0,5);
Environment->addStaticText(L"Texture...", textRect, false, false, this );
textRect += shiftY;
textureNameEditBox = Environment->addEditBox( L"", textRect, true, this, -1);
textureNameEditBox->setEnabled(false);
recti textureButtonRect( vector2di(0,0), dimension2d<s32>(textRect.getHeight(), textRect.getHeight()) );
textureButtonRect += vector2di( textRect.LowerRightCorner.X + 5, textRect.UpperLeftCorner.Y );
textureSelectButton = Environment->addButton( textureButtonRect, this, -1, L"...", L"Select texture." );
textureButtonRect += vector2di( textureButtonRect.getWidth() + 5, 0 );
textureRemoveButton = Environment->addButton( textureButtonRect, this, -1, L"", L"Remove texture." );
textureRemoveButton->setSpriteBank( Environment->getSkin()->getSpriteBank() );
textureRemoveButton->setSprite(
EGBS_BUTTON_NOT_FOCUSED,
Environment->getSkin()->getIcon( EGDI_WINDOW_CLOSE ),
Environment->getSkin()->getColor( EGDC_WINDOW_SYMBOL )
);
textureRemoveButton->setSprite(
EGBS_BUTTON_FOCUSED,
Environment->getSkin()->getIcon( EGDI_WINDOW_CLOSE ),
Environment->getSkin()->getColor( EGDC_WINDOW_SYMBOL )
);
// ********* Mesh scene
// create GUI Mesh Scene with sphere with material
core::dimension2di sceneSize;
sceneSize.Width = pRect.getWidth() * 2 / 3;
sceneSize.Height = sceneSize.Width;
meshMaterialScene = new GUIScene(
Environment,
pSceneManager,
this,
recti(
vector2di(0, textRect.LowerRightCorner.Y + 15),
sceneSize
)
);
materialSceneNode = meshMaterialScene->GetScene()->addCubeSceneNode();
meshMaterialScene->SetOptimalCamDistToNode( materialSceneNode );
meshMaterialScene->enableCamControl(true);
meshMaterialScene->setExtraCamDistance(5);
meshMaterialScene->setDrawBorder(true);
}
GUIMaterialPanel::~GUIMaterialPanel()
{
closeWindows();
if ( ambientColorEditBox )
ambientColorEditBox->drop();
if ( diffuseColorEditBox )
diffuseColorEditBox->drop();
if ( emissiveColorEditBox )
emissiveColorEditBox->drop();
if ( specularColorEditBox )
specularColorEditBox->drop();
}
void GUIMaterialPanel::closeWindows()
{
if ( ambientColorSelectWindow )
{
ambientColorSelectWindow->remove();
ambientColorSelectWindow = 0;
ambientColorSelect = 0;
}
if ( diffuseColorSelectWindow )
{
diffuseColorSelectWindow->remove();
diffuseColorSelectWindow = 0;
diffuseColorSelect = 0;
}
if ( emissiveColorSelectWindow )
{
emissiveColorSelectWindow->remove();
emissiveColorSelectWindow = 0;
emissiveColorSelect = 0;
}
if ( specularColorSelectWindow )
{
specularColorSelectWindow->remove();
specularColorSelectWindow = 0;
specularColorSelect = 0;
}
}
void GUIMaterialPanel::setMaterial( SMaterial& pMaterial )
{
material = &pMaterial;
// Update everything
ambientColorEditBox->setColor( pMaterial.AmbientColor, false );
ambientPanelSample->showOneColor( pMaterial.AmbientColor );
diffuseColorEditBox->setColor( pMaterial.DiffuseColor, false );
diffusePanelSample->showOneColor( pMaterial.DiffuseColor );
emissiveColorEditBox->setColor( pMaterial.EmissiveColor, false );
emissivePanelSample->showOneColor( pMaterial.EmissiveColor );
specularColorEditBox->setColor( pMaterial.SpecularColor, false );
specularPanelSample->showOneColor( pMaterial.SpecularColor );
if ( ambientColorSelectWindow )
{
ambientColorSelect->setColor( pMaterial.AmbientColor, false );
ambientColorSample->showOneColor( pMaterial.AmbientColor );
}
if ( diffuseColorSelectWindow )
{
diffuseColorSelect->setColor( pMaterial.DiffuseColor, false );
diffuseColorSample->showOneColor( pMaterial.DiffuseColor );
}
if ( emissiveColorSelectWindow )
{
emissiveColorSelect->setColor( pMaterial.EmissiveColor, false );
emissiveColorSample->showOneColor( pMaterial.EmissiveColor );
}
if ( specularColorSelectWindow )
{
specularColorSelect->setColor( pMaterial.SpecularColor, false );
specularColorSample->showOneColor( pMaterial.SpecularColor );
}
wireframeCheckbox->setChecked( pMaterial.Wireframe );
gourandShadingCheckbox->setChecked( pMaterial.GouraudShading );
lightingCheckbox->setChecked( pMaterial.Lighting );
mipmapsCheckbox->setChecked( pMaterial.UseMipMaps );
if ( pMaterial.getTexture(0) )
{
textureNameEditBox->setText( stringw(pMaterial.getTexture(0)->getName().getPath()).c_str() );
} else {
textureNameEditBox->setText(L"");
}
meshMaterialScene->setDrawBackground( ! pMaterial.Wireframe );
updateMeshScene();
}
void GUIMaterialPanel::setAmbientLight( irr::video::SColor pColor )
{
meshMaterialScene->GetScene()->setAmbientLight( pColor );
}
bool GUIMaterialPanel::OnEvent( const SEvent& event )
{
// Only respond to GUI events
if ( isEnabled() && isVisible() )
switch ( event.EventType )
{
case EET_GUI_EVENT:
if ( OnGuiEvent(event) )
return true;
break;
default: break;
}
return IGUIElement::OnEvent(event);
}
bool GUIMaterialPanel::OnGuiEvent( const SEvent& event )
{
switch ( event.GUIEvent.EventType )
{
case EGET_EDITBOX_CHANGED:
if ( event.GUIEvent.Caller == ambientColorEditBox )
{
if ( ambientColorSelectWindow )
{
ambientColorSelect->setColor( ambientColorEditBox->getColor(), false );
ambientColorSample->showOneColor( ambientColorEditBox->getColor() );
}
if ( material )
material->AmbientColor = ambientColorEditBox->getColor();
ambientPanelSample->showOneColor( ambientColorEditBox->getColor() );
sendGUIEvent( EGET_EDITBOX_CHANGED, ambientColorEditBox );
return true;
}
else if ( event.GUIEvent.Caller == ambientColorSelect )
{
ambientColorEditBox->setColor( ambientColorSelect->getColor(), false );
ambientPanelSample->showOneColor( ambientColorSelect->getColor() );
ambientColorSample->showOneColor( ambientColorSelect->getColor() );
if ( material )
material->AmbientColor = ambientColorSelect->getColor();
sendGUIEvent( EGET_EDITBOX_CHANGED, ambientColorSelect );
return true;
}
else if ( event.GUIEvent.Caller == diffuseColorEditBox )
{
if ( diffuseColorSelectWindow )
{
diffuseColorSelect->setColor( diffuseColorEditBox->getColor(), false );
diffuseColorSample->showOneColor( diffuseColorEditBox->getColor() );
}
if ( material )
material->DiffuseColor = diffuseColorEditBox->getColor();
diffusePanelSample->showOneColor( diffuseColorEditBox->getColor() );
sendGUIEvent( EGET_EDITBOX_CHANGED, diffuseColorEditBox );
return true;
}
else if ( event.GUIEvent.Caller == diffuseColorSelect )
{
diffuseColorEditBox->setColor( diffuseColorSelect->getColor(), false );
diffusePanelSample->showOneColor( diffuseColorSelect->getColor() );
diffuseColorSample->showOneColor( diffuseColorSelect->getColor() );
if ( material )
material->DiffuseColor = diffuseColorSelect->getColor();
sendGUIEvent( EGET_EDITBOX_CHANGED, diffuseColorSelect );
return true;
}
else if ( event.GUIEvent.Caller == emissiveColorEditBox )
{
if ( emissiveColorSelectWindow )
{
emissiveColorSelect->setColor( emissiveColorEditBox->getColor(), false );
emissiveColorSample->showOneColor( emissiveColorEditBox->getColor() );
}
if ( material )
material->EmissiveColor = emissiveColorEditBox->getColor();
emissivePanelSample->showOneColor( emissiveColorEditBox->getColor() );
sendGUIEvent( EGET_EDITBOX_CHANGED, emissiveColorEditBox );
return true;
}
else if ( event.GUIEvent.Caller == emissiveColorSelect )
{
emissiveColorEditBox->setColor( emissiveColorSelect->getColor(), false );
emissivePanelSample->showOneColor( emissiveColorSelect->getColor() );
emissiveColorSample->showOneColor( emissiveColorSelect->getColor() );
if ( material )
material->EmissiveColor = emissiveColorSelect->getColor();
sendGUIEvent( EGET_EDITBOX_CHANGED, emissiveColorSelect );
return true;
}
else if ( event.GUIEvent.Caller == specularColorEditBox )
{
if ( specularColorSelectWindow )
{
specularColorSelect->setColor( specularColorEditBox->getColor(), false );
specularColorSample->showOneColor( specularColorEditBox->getColor() );
}
if ( material )
material->SpecularColor = specularColorEditBox->getColor();
specularPanelSample->showOneColor( specularColorEditBox->getColor() );
sendGUIEvent( EGET_EDITBOX_CHANGED, specularColorEditBox );
return true;
}
else if ( event.GUIEvent.Caller == specularColorSelect )
{
specularColorEditBox->setColor( specularColorSelect->getColor(), false );
specularPanelSample->showOneColor( specularColorSelect->getColor() );
specularColorSample->showOneColor( specularColorSelect->getColor() );
if ( material )
material->SpecularColor = specularColorSelect->getColor();
sendGUIEvent( EGET_EDITBOX_CHANGED, specularColorSelect );
return true;
}
break; //end case EGET_EDITBOX_CHANGED
case EGET_BUTTON_CLICKED:
if ( event.GUIEvent.Caller == ambientColorButton )
{
closeWindows(); // Prevent windows from tying into eachother
if ( !ambientColorSelectWindow )
{
recti r (colorSelectWindowRect);
r.UpperLeftCorner += vector2di(5, 25);
r.LowerRightCorner -= vector2di(5);
// Room for the color sample
r.LowerRightCorner.X -= 50;
ambientColorSelectWindow = createColorSelectWindow();
ambientColorSelect = new GUISColorSelect(
Environment,
ambientColorSelectWindow,
r);
ambientColorSelect->drop(); // balance reference counting
r.UpperLeftCorner.X = r.LowerRightCorner.X + 20;
r.LowerRightCorner.X = colorSelectWindowRect.LowerRightCorner.X - 10;
ambientColorSample = new GUIColorSample(
Environment,
ambientColorSelectWindow,
r);
ambientColorSample->setDrawBorder(true);
ambientColorSample->drop(); // balance reference counting
}
ambientColorSelect->setColor( ambientColorEditBox->getColor(), false );
ambientColorSample->showOneColor( ambientColorEditBox->getColor() );
Environment->getRootGUIElement()->bringToFront( ambientColorSelectWindow );
Environment->setFocus( ambientColorSelectWindow );
return true;
}
else if ( event.GUIEvent.Caller == diffuseColorButton )
{
closeWindows(); // Prevent windows from tying into eachother
if ( !diffuseColorSelectWindow )
{
recti r (colorSelectWindowRect);
r.UpperLeftCorner += vector2di(5, 25);
r.LowerRightCorner -= vector2di(5);
// Room for the color sample
r.LowerRightCorner.X -= 50;
diffuseColorSelectWindow = createColorSelectWindow();
diffuseColorSelect = new GUISColorSelect(
Environment,
diffuseColorSelectWindow,
r);
diffuseColorSelect->drop(); // balance reference counting
r.UpperLeftCorner.X = r.LowerRightCorner.X + 20;
r.LowerRightCorner.X = colorSelectWindowRect.LowerRightCorner.X - 10;
diffuseColorSample = new GUIColorSample(
Environment,
diffuseColorSelectWindow,
r);
diffuseColorSample->setDrawBorder(true);
diffuseColorSample->drop(); // balance reference counting
}
diffuseColorSelect->setColor( diffuseColorEditBox->getColor(), false );
diffuseColorSample->showOneColor( diffuseColorEditBox->getColor() );
Environment->getRootGUIElement()->bringToFront( diffuseColorSelectWindow );
Environment->setFocus( diffuseColorSelectWindow );
return true;
}
else if ( event.GUIEvent.Caller == emissiveColorButton )
{
closeWindows(); // Prevent windows from tying into eachother
if ( !emissiveColorSelectWindow )
{
recti r (colorSelectWindowRect);
r.UpperLeftCorner += vector2di(5, 25);
r.LowerRightCorner -= vector2di(5);
// Room for the color sample
r.LowerRightCorner.X -= 50;
emissiveColorSelectWindow = createColorSelectWindow();
emissiveColorSelect = new GUISColorSelect(
Environment,
emissiveColorSelectWindow,
r);
emissiveColorSelect->drop(); // balance reference counting
r.UpperLeftCorner.X = r.LowerRightCorner.X + 20;
r.LowerRightCorner.X = colorSelectWindowRect.LowerRightCorner.X - 10;
emissiveColorSample = new GUIColorSample(
Environment,
emissiveColorSelectWindow,
r);
emissiveColorSample->setDrawBorder(true);
emissiveColorSample->drop(); // balance reference counting
}
emissiveColorSelect->setColor( emissiveColorEditBox->getColor(), false );
emissiveColorSample->showOneColor( emissiveColorEditBox->getColor() );
Environment->getRootGUIElement()->bringToFront( emissiveColorSelectWindow );
Environment->setFocus( emissiveColorSelectWindow );
return true;
}
else if ( event.GUIEvent.Caller == specularColorButton )
{
closeWindows(); // Prevent windows from tying into eachother
if ( !specularColorSelectWindow )
{
recti r (colorSelectWindowRect);
r.UpperLeftCorner += vector2di(5, 25);
r.LowerRightCorner -= vector2di(5);
// Room for the color sample
r.LowerRightCorner.X -= 50;
specularColorSelectWindow = createColorSelectWindow();
specularColorSelect = new GUISColorSelect(
Environment,
specularColorSelectWindow,
r);
specularColorSelect->drop(); // balance reference counting
r.UpperLeftCorner.X = r.LowerRightCorner.X + 20;
r.LowerRightCorner.X = colorSelectWindowRect.LowerRightCorner.X - 10;
specularColorSample = new GUIColorSample(
Environment,
specularColorSelectWindow,
r);
specularColorSample->setDrawBorder(true);
specularColorSample->drop(); // balance reference counting
}
specularColorSelect->setColor( specularColorEditBox->getColor(), false );
specularColorSample->showOneColor( specularColorEditBox->getColor() );
Environment->getRootGUIElement()->bringToFront( specularColorSelectWindow );
Environment->setFocus( specularColorSelectWindow );
return true;
}
else if ( event.GUIEvent.Caller == textureSelectButton )
{
createSelectTextureDialog();
return true;
}
else if ( event.GUIEvent.Caller == textureRemoveButton )
{
if ( material )
{
material->setTexture(0,0);
}
updateMeshScene();
textureNameEditBox->setText(L"");
return true;
}
break; // end case EGET_BUTTON_CLICKED
case EGET_CHECKBOX_CHANGED:
if ( event.GUIEvent.Caller == wireframeCheckbox )
{
if ( material )
material->Wireframe = wireframeCheckbox->isChecked();
meshMaterialScene->setDrawBackground( ! wireframeCheckbox->isChecked() );
sendGUIEvent( EGET_CHECKBOX_CHANGED, wireframeCheckbox );
return true;
}
else if ( event.GUIEvent.Caller == gourandShadingCheckbox )
{
if ( material )
material->GouraudShading = gourandShadingCheckbox->isChecked();
sendGUIEvent( EGET_CHECKBOX_CHANGED, gourandShadingCheckbox );
return true;
}
else if ( event.GUIEvent.Caller == lightingCheckbox )
{
if ( material )
material->Lighting = lightingCheckbox->isChecked();
sendGUIEvent( EGET_CHECKBOX_CHANGED, lightingCheckbox );
return true;
}
else if ( event.GUIEvent.Caller == mipmapsCheckbox )
{
if ( material )
material->UseMipMaps = mipmapsCheckbox->isChecked();
sendGUIEvent( EGET_CHECKBOX_CHANGED, mipmapsCheckbox );
return true;
}
break; // end case EGET_CHECKBOX_CHANGED
case EGET_ELEMENT_CLOSED:
// And we hope this doesn't cause memory leaks
if ( event.GUIEvent.Caller == ambientColorSelectWindow )
{
ambientColorSelectWindow = 0;
ambientColorSelect = 0;
}
else if ( event.GUIEvent.Caller == diffuseColorSelectWindow )
{
diffuseColorSelectWindow = 0;
diffuseColorSelect = 0;
}
else if ( event.GUIEvent.Caller == emissiveColorSelectWindow )
{
emissiveColorSelectWindow = 0;
emissiveColorSelect = 0;
}
else if ( event.GUIEvent.Caller == specularColorSelectWindow )
{
specularColorSelectWindow = 0;
specularColorSelect = 0;
}
break; // end case EGET_ELEMENT_CLOSED
case EGET_FILE_SELECTED:
if ( event.GUIEvent.Caller == selectTextureFilePanel )
{
switch ( selectTextureFilePanel->getLastEvent() )
{
case EGFSPE_FILE_CONFIRMED:
if ( material )
{
material->setTexture(0,
Environment->getVideoDriver()->getTexture(
selectTextureFilePanel->getSelectedFile()
)
);
if ( material->getTexture(0) )
{
textureNameEditBox->setText( stringw(selectTextureFilePanel->getSelectedFile()).c_str() );
updateMeshScene();
}
}
selectTextureWindow->remove();
selectTextureWindow = 0;
selectTextureFilePanel = 0;
break;
default:
break;
}
}
break;
case EGET_FILE_CHOOSE_DIALOG_CANCELLED:
if ( event.GUIEvent.Caller == selectTextureFilePanel )
{
selectTextureWindow->remove();
selectTextureWindow = 0;
selectTextureFilePanel = 0;
}
break;
default: break;
}
return false;
}
void GUIMaterialPanel::sendGUIEvent( EGUI_EVENT_TYPE pEventType, IGUIElement* pElement )
{
updateMeshScene();
if ( ! Parent ) return;
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = pElement;
event.GUIEvent.EventType = pEventType;
Parent->OnEvent(event);
}
void GUIMaterialPanel::updateMeshScene()
{
if ( !material )
return;
// There should be at least one
if ( materialSceneNode->getMaterialCount() )
{
materialSceneNode->getMaterial(0) = *material;
}
}
IGUIWindow* GUIMaterialPanel::createColorSelectWindow()
{
s32 bumpX = 5, bumpY = 5;
recti r(colorSelectWindowRect);
r.UpperLeftCorner -= vector2di( bumpX, bumpY );
//r.LowerRightCorner += vector2di( 50, 0 );
// Center in root window
dimension2d<s32> ss = Environment->getRootGUIElement()->getAbsolutePosition().getSize() / 2;
dimension2d<s32> rs = r.getSize() / 2;
vector2di startPos( ss.Width - rs.Width, ss.Height - rs.Height );
//IGUIWindow* window = Environment->addWindow( r, false, 0, this, -1 );
GUIWindow2* window = new GUIWindow2( Environment, Environment->getRootGUIElement(), r );
window->setEventParent( this );
window->setNotClipped(true); // Does not allow full roaming
window->setDraggable(true);
window->setDrawBackground(true);
window->setDrawTitlebar(true); // space for close button
window->getMinimizeButton()->remove();
window->getMaximizeButton()->remove();
window->move( startPos );
window->drop(); // balance reference counting
return window;
}
void GUIMaterialPanel::createSelectTextureDialog()
{
dimension2di windowSize(400,300);
dimension2di rootGUISize = Environment->getRootGUIElement()->getAbsolutePosition().getSize();
recti windowRect(
vector2di( rootGUISize.Width - windowSize.Width,
rootGUISize.Height - windowSize.Height )/2,
windowSize
);
IGUIElement* modalScreen = Environment->addModalScreen(Environment->getRootGUIElement());
selectTextureWindow = new GUIWindow2( Environment, 0, windowRect );
selectTextureWindow->setEventParent(this);
modalScreen->addChild( selectTextureWindow );
selectTextureWindow->getMinimizeButton()->remove();
selectTextureFilePanel = new GUIFileSelectPanel(
Environment,
selectTextureWindow,
selectTextureWindow->getClientRect(),
io::path(".")
);
selectTextureWindow->drop();
selectTextureFilePanel->drop();
}
}
}

View File

@ -0,0 +1,136 @@
// (c) 2014 Nicolaus Anderson
#include <IGUIElement.h>
#ifndef GUI_MATERIAL_PANEL_H_
#define GUI_MATERIAL_PANEL_H_
namespace irr {
namespace scene {
class ISceneManager;
class IMeshSceneNode;
}
namespace video {
class SColor;
class SMaterial;
}
namespace gui {
using core::vector2di;
using core::recti;
using video::SMaterial;
using scene::ISceneManager;
using scene::IMeshSceneNode;
class IGUIButton;
class IGUICheckBox;
class IGUIWindow;
class IGUIEditBox;
class GUIColorEditBox;
class GUIColorSample;
class GUISColorSelect;
class GUIScene;
class GUIWindow2;
class GUIFileSelectPanel;
/* Class : GUI Material Panel
This creates a panel with buttons for opening color-selection windows,
editboxes for editing the colors (ambient, diffuse, emissive, and specular),
and checkboxes for turning on the engine-features of wireframe drawing,
gouraud shading, making the material lit by lights, and having the
engine generate mipmaps for the material textures.
It is not possible to remove any of these items.
In the future, the buttons, editboxes, and checkboxes should be removable,
but this requires grabbing them in the constructor after they have been
created and dropping them in the deconstructor.
The design of this class is such that it can handle all of the material
editing without the programmer having to monitor its events and update
changes to the material accordingly. Pass a pointer to the material
via setMaterial().
Optionally, this panel should have a 3D mesh scene that shows a sphere,
indicating what the material looks like when applied to a scene node.
*/
class GUIMaterialPanel : public IGUIElement
{
protected:
SMaterial* material;
GUIScene* meshMaterialScene;
IMeshSceneNode* materialSceneNode;
GUIColorEditBox* ambientColorEditBox;
GUIColorSample* ambientPanelSample;
IGUIButton* ambientColorButton;
IGUIWindow* ambientColorSelectWindow;
GUISColorSelect* ambientColorSelect;
GUIColorSample* ambientColorSample;
GUIColorEditBox* diffuseColorEditBox;
GUIColorSample* diffusePanelSample;
IGUIButton* diffuseColorButton;
IGUIWindow* diffuseColorSelectWindow;
GUISColorSelect* diffuseColorSelect;
GUIColorSample* diffuseColorSample;
GUIColorEditBox* emissiveColorEditBox;
GUIColorSample* emissivePanelSample;
IGUIButton* emissiveColorButton;
IGUIWindow* emissiveColorSelectWindow;
GUISColorSelect* emissiveColorSelect;
GUIColorSample* emissiveColorSample;
GUIColorEditBox* specularColorEditBox;
GUIColorSample* specularPanelSample;
IGUIButton* specularColorButton;
IGUIWindow* specularColorSelectWindow;
GUISColorSelect* specularColorSelect;
GUIColorSample* specularColorSample;
IGUICheckBox* wireframeCheckbox;
IGUICheckBox* gourandShadingCheckbox;
IGUICheckBox* lightingCheckbox;
IGUICheckBox* mipmapsCheckbox;
recti colorSelectWindowRect;
IGUIEditBox* textureNameEditBox;
IGUIButton* textureSelectButton;
IGUIButton* textureRemoveButton;
GUIWindow2* selectTextureWindow;
GUIFileSelectPanel* selectTextureFilePanel;
public:
GUIMaterialPanel( IGUIEnvironment* pEnvironment, ISceneManager* pSceneManager, IGUIElement* pParent, recti pRect, s32 id=-1 );
~GUIMaterialPanel();
void setMaterial( SMaterial& pMaterial );
void closeWindows();
void setAmbientLight( irr::video::SColor pColor );
virtual bool OnEvent( const SEvent& event );
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "materialPanel"; }
protected:
bool OnGuiEvent( const SEvent& event );
void sendGUIEvent( EGUI_EVENT_TYPE pEventType, IGUIElement* pElement=0 );
// Set the mesh material to a copy of the one pointed to by "material".
void updateMeshScene();
IGUIWindow* createColorSelectWindow();
void createSelectTextureDialog();
};
}
}
#endif

View File

@ -0,0 +1,244 @@
// (c) 2015 Nicolaus Anderson
#ifndef GUI_MATRIX_PANEL_CPP
#define GUI_MATRIX_PANEL_CPP
#include "GUIMatrixPanel.h"
#include "GUIVectorPanel.h"
#include <IGUIEnvironment.h>
#include <IGUIFont.h>
#include <IGUISkin.h>
#include <IGUIStaticText.h>
namespace irr {
namespace gui {
using core::dimension2d;
using core::vector2di;
GUIMatrixPanel::GUIMatrixPanel( bool pRotateInDegrees, IGUIEnvironment* pEnvironment, IGUIElement* pParent, rect<s32> pRect, s32 id )
: IGUIElement( EGUIET_ELEMENT, pEnvironment, pParent, id, pRect )
, translationVectorPanel(0)
, rotationVectorPanel(0)
, scaleVectorPanel(0)
, rotInDeg( pRotateInDegrees )
{
// labelSpan = for "Translation", "Rotation", and "Scale" text
// xyzSpan = for "X", "Y", and "Z" text
/* Intended appearance:
labelSpan -pad- xyzSpan xyzSpan xyzSpan
labelSpan -pad- vectorPanel
labelSpan -pad- vectorPanel
labelSpan -pad- vectorPanel
*/
s32 pad = 3; // padding between elements
dimension2d<u32> labelSpan = pEnvironment->getSkin()->getFont()->getDimension(L"Translate");
s32 boxH = (pRect.getHeight() - (3*pad)) / 4; // used regardless of the text height
s32 xyzSpan = ( pRect.getWidth() - (s32)labelSpan.Width - (pad*2) ) / 3;
rect<s32> labelRect( 0, boxH, labelSpan.Width, boxH*2 ); // for "Translate", "Rotate", and "Scale"
rect<s32> textRect( 0, 0, boxH, boxH ); // for "X", "Y", and "Z"
textRect += vector2di( xyzSpan/2 - 3, boxH/2 - 3 ); // text centering
// Add labels of X, Y, and Z to the top
// Note the first is indented so it doesn't hover over the labels
textRect += vector2di( labelSpan.Width + pad, 0 ); // Use .move() with custom Irrlicht
IGUIStaticText* textElem =
pEnvironment->addStaticText( L"X", textRect, false, false, this, -1, false ); // no border, wordwrap, nor fill
textElem->setAlignment( EGUIA_UPPERLEFT, EGUIA_SCALE, EGUIA_SCALE, EGUIA_SCALE );
textRect += vector2di( xyzSpan, 0 ); // Use .move() with custom Irrlicht
textElem =
pEnvironment->addStaticText( L"Y", textRect, false, false, this, -1, false ); // no border, wordwrap, nor fill
textElem->setAlignment( EGUIA_SCALE, EGUIA_SCALE, EGUIA_SCALE, EGUIA_SCALE );
textRect += vector2di( xyzSpan, 0 ); // Use .move() with custom Irrlicht
textElem = pEnvironment->addStaticText( L"Z", textRect, false, false, this, -1, false ); // no border, wordwrap, nor fill
textElem->setAlignment( EGUIA_SCALE, EGUIA_SCALE, EGUIA_SCALE, EGUIA_SCALE );
// Add the labels of "Translate", "Rotate", and "Scale"
textElem = pEnvironment->addStaticText( L"Translate", labelRect, false, false, this, -1, false );
textElem->setAlignment( EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_SCALE, EGUIA_SCALE );
labelRect += vector2di( 0, boxH + pad ); // Use .move() with custom Irrlicht
textElem = pEnvironment->addStaticText( L"Rotate", labelRect, false, false, this, -1, false );
textElem->setAlignment( EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_SCALE, EGUIA_SCALE );
labelRect += vector2di( 0, boxH + pad ); // Use .move() with custom Irrlicht
textElem = pEnvironment->addStaticText( L"Scale", labelRect, false, false, this, -1, false );
textElem->setAlignment( EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_SCALE, EGUIA_SCALE );
// Add the vector panels
rect<s32> vectorPanelRect( labelSpan.Width + pad, boxH + pad, pRect.getWidth(), boxH*2 + pad );
translationVectorPanel = new GUIVectorPanel( pEnvironment, this, vectorPanelRect, true );
//translationVectorPanel->setAlignment( EGUIA_UPPERLEFT, EGUIA_SCALE, EGUIA_SCALE, EGUIA_SCALE );
vectorPanelRect += vector2di( 0, boxH + pad ); // Use .move() with custom Irrlicht
rotationVectorPanel = new GUIVectorPanel( pEnvironment, this, vectorPanelRect, true );
//rotationVectorPanel->setAlignment( EGUIA_UPPERLEFT, EGUIA_SCALE, EGUIA_SCALE, EGUIA_SCALE );
vectorPanelRect += vector2di( 0, boxH + pad ); // Use .move() with custom Irrlicht
scaleVectorPanel = new GUIVectorPanel( pEnvironment, this, vectorPanelRect, true );
//scaleVectorPanel->setAlignment( EGUIA_UPPERLEFT, EGUIA_SCALE, EGUIA_SCALE, EGUIA_SCALE );
}
/*
matrix4 GUIMatrixPanel::getMatrix()
{
// The problem is that setScale and setRotation conflict, causing one to override the other
matrix4 m;
m.setScale( getScale() );
m.setRotation( getRotation() );
m.setTranslation( getTranslation() );
return m;
}
*/
void GUIMatrixPanel::setSpaceMatrix( SpaceMatrix& pMatrix )
{
//spaceMatrix = pMatrix;
translationVectorPanel->set3DVectorValue( pMatrix.getTranslation() );
scaleVectorPanel->set3DVectorValue( pMatrix.getScale() );
if ( rotInDeg )
rotationVectorPanel->set3DVectorValue( pMatrix.getRotationDegrees() );
else
rotationVectorPanel->set3DVectorValue( pMatrix.getRotationRadians() );
}
void GUIMatrixPanel::setTranslation( vector3d<f32> pTranslation )
{
//spaceMatrix->setTranslation( pTranslation );
translationVectorPanel->set3DVectorValue( pTranslation );
}
void GUIMatrixPanel::setRotation( vector3d<f32> pRotation )
{
rotationVectorPanel->set3DVectorValue( pRotation );
}
void GUIMatrixPanel::setScale( vector3d<f32> pScale )
{
scaleVectorPanel->set3DVectorValue( pScale );
}
SpaceMatrix GUIMatrixPanel::getSpaceMatrix()
{
if ( !rotInDeg )
return SpaceMatrix(
translationVectorPanel->getVector3D(),
rotationVectorPanel->getVector3D(),
scaleVectorPanel->getVector3D()
);
// else, must convert from degrees
SpaceMatrix m = SpaceMatrix(
translationVectorPanel->getVector3D(),
vector3d<f32>(),
scaleVectorPanel->getVector3D()
);
m.setRotationDegrees( rotationVectorPanel->getVector3D() );
return m;
}
vector3d<f32> GUIMatrixPanel::getTranslation()
{
return translationVectorPanel->getVector3D();
}
vector3d<f32> GUIMatrixPanel::getRotation()
{
return rotationVectorPanel->getVector3D();
}
vector3d<f32> GUIMatrixPanel::getScale()
{
return scaleVectorPanel->getVector3D();
}
void GUIMatrixPanel::reset()
{
translationVectorPanel->reset();
rotationVectorPanel->reset();
scaleVectorPanel->set3DValue(1.f, 1.f, 1.f);
}
bool GUIMatrixPanel::OnEvent( const SEvent& event )
{
if ( !isVisible() || !isEnabled() || event.EventType != EET_GUI_EVENT )
return false;
if ( event.GUIEvent.Caller == translationVectorPanel )
{
lastAction = EGUIMTXPA_TranslationChanged;
//spaceMatrix->setTranslation( translationVectorPanel->getVector3D() );
sendGUIEvent( EGET_EDITBOX_CHANGED, translationVectorPanel );
return true;
} else if ( event.GUIEvent.Caller == rotationVectorPanel )
{
lastAction = EGUIMTXPA_RotationChanged;
//spaceMatrix->setRotationDegrees( rotationVectorPanel->getVector3D() );
sendGUIEvent( EGET_EDITBOX_CHANGED, rotationVectorPanel );
return true;
} else if ( event.GUIEvent.Caller == scaleVectorPanel )
{
lastAction = EGUIMTXPA_ScaleChanged;
//spaceMatrix->setScale( scaleVectorPanel->getVector3D() );
sendGUIEvent( EGET_EDITBOX_CHANGED, scaleVectorPanel );
return true;
}
lastAction = EGUIMTXPA_None;
return false;
}
void GUIMatrixPanel::sendGUIEvent( EGUI_EVENT_TYPE pEventType, IGUIElement* pElement )
{
if ( ! Parent ) return;
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = pElement;
event.GUIEvent.EventType = pEventType;
Parent->OnEvent(event);
}
EGUIMatrixPanelAction GUIMatrixPanel::getLastAction()
{
return lastAction;
}
bool GUIMatrixPanel::rotatesInDegrees()
{
return rotInDeg;
}
void GUIMatrixPanel::serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options
)
{
IGUIElement::serializeAttributes(out,options);
out->addBool("RotateInDegrees", rotInDeg);
}
void GUIMatrixPanel::deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options
)
{
IGUIElement::deserializeAttributes(in,options);
rotInDeg = in->getAttributeAsBool("RotateInDegrees", rotInDeg);
}
}}
#endif // #ifndef GUI_MATRIX_PANEL_CPP

View File

@ -0,0 +1,88 @@
// (c) 2015 Nicolaus Anderson
#ifndef GUI_MATRIX_PANEL_H
#define GUI_MATRIX_PANEL_H
#include <vector3d.h>
#include <IGUIElement.h>
// #include <matrix4.h>
#include "../math/SpaceMatrix.h"
namespace irr {
namespace gui {
using core::vector3d;
using core::rect;
using core::matrix4;
class GUIVectorPanel;
//! Enum GUI Matrix Panel Action
/* Used for indicating the last action of the matrix.
It is also designed to save time in calculating the full space matrix (something that may never need to be done). */
enum EGUIMatrixPanelAction
{
EGUIMTXPA_None = 0,
EGUIMTXPA_TranslationChanged,
EGUIMTXPA_RotationChanged,
EGUIMTXPA_ScaleChanged,
EGUIMTXPA_COUNT
};
//! Class GUI Matrix Panel
/* Allows for the easy editing of a matrix. */
class GUIMatrixPanel : public IGUIElement
{
protected:
GUIVectorPanel* translationVectorPanel;
GUIVectorPanel* rotationVectorPanel;
GUIVectorPanel* scaleVectorPanel;
//SpaceMatrix spaceMatrix;
private:
EGUIMatrixPanelAction lastAction;
bool rotInDeg;
public:
GUIMatrixPanel( bool pRotateInDegrees, IGUIEnvironment* pEnvironment, IGUIElement* pParent, rect<s32> pRect, s32 id=-1 );
//matrix4 getMatrix();
void setSpaceMatrix( SpaceMatrix& pMatrix );
void setTranslation( vector3d<f32> pTranslation );
void setRotation( vector3d<f32> pRotation );
void setScale( vector3d<f32> pScale );
SpaceMatrix getSpaceMatrix();
vector3d<f32> getTranslation();
vector3d<f32> getRotation();
vector3d<f32> getScale();
void reset();
virtual bool OnEvent( const SEvent& event );
EGUIMatrixPanelAction getLastAction();
// Matrix uses degrees for rotation
/* Indicates if this panel keeps its rotation in degrees instead of radians.
The returned matrix from getSpaceMatrix() will be converted to radians, but
getRotation() will be returned with degrees. */
bool rotatesInDegrees();
virtual void serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options=0
);
virtual void deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options=0
);
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "matrixPanel"; }
private:
void sendGUIEvent( EGUI_EVENT_TYPE pEventType, IGUIElement* pElement );
};
}}
#endif // #ifndef GUI_MATRIX_PANEL_H

View File

@ -0,0 +1,74 @@
// (C) 2020 Nicolaus Anderson
#include "GUIPanel.h"
namespace irr {
namespace gui {
GUIPanel::GUIPanel( IGUIEnvironment* environment, IGUIElement* parent, const core::recti& position, s32 id )
: IGUIElement(EGUIET_ELEMENT, environment, parent, id, position)
, DrawBackground(true)
, BackgroundType(EGUIDT_SUNKENPANE)
, BackgroundColor(0xff707070)
, DrawTitleBar(false)
, TitleBarColor(0xffc0c0c0)
{}
void GUIPanel::setDrawBackground( bool yes )
{
DrawBackground = yes;
}
void GUIPanel::setBackgroundType( EGUIDrawType type )
{
BackgroundType = type;
}
void GUIPanel::draw()
{
switch(BackgroundType) {
case EGUIDT_BUTTON:
Environment->getSkin()->draw3DButtonPaneStandard(this, AbsoluteRect, &AbsoluteClippingRect);
break;
case EGUIDT_BUTTON_PRESSED:
Environment->getSkin()->draw3DButtonPanePressed(this, AbsoluteRect, &AbsoluteClippingRect);
break;
case EGUIDT_SUNKENPANE:
Environment->getSkin()->draw3DSunkenPane(this, BackgroundColor, false, true, AbsoluteRect, &AbsoluteClippingRect);
break;
case EGUIDT_WINDOW:
Environment->getSkin()->draw3DWindowBackground(this, DrawTitleBar, TitleBarColor, AbsoluteRect, &AbsoluteClippingRect);
break;
default:
break;
}
}
void GUIPanel::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
IGUIElement::serializeAttributes(out, options);
out->addBool( "DrawBackground", DrawBackground );
out->addEnum( "BackgroundType", BackgroundType, GUIDrawTypeNames );
out->addColor( "BackgroundColor", BackgroundColor );
out->addBool( "DrawTitleBar", DrawTitleBar );
out->addColor( "TitleBarColor", TitleBarColor);
}
void GUIPanel::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
IGUIElement::deserializeAttributes(in, options);
DrawBackground = in->getAttributeAsBool( "DrawBackground", DrawBackground );
BackgroundType = (EGUIDrawType)in->getAttributeAsEnumeration( "BackgroundType", GUIDrawTypeNames, BackgroundType );
BackgroundColor = in->getAttributeAsColor( "BackgroundColor", BackgroundColor );
DrawTitleBar = in->getAttributeAsBool( "DrawTitleBar", DrawTitleBar );
TitleBarColor = in->getAttributeAsColor( "TitleBarColor", TitleBarColor );
}
}
}

View File

@ -0,0 +1,56 @@
// (C) 2020 Nicolaus Anderson
/*
A convenient GUI element whose standard appearance can be changed to mimic that of other elements.
*/
#ifndef GUI_PANEL_H
#define GUI_PANEL_H
#include <IGUIElement.h>
#include <IGUIEnvironment.h>
#include <IGUISkin.h>
namespace irr {
namespace gui {
enum EGUIDrawType {
EGUIDT_BUTTON,
EGUIDT_BUTTON_PRESSED,
EGUIDT_SUNKENPANE,
EGUIDT_WINDOW,
};
const c8* const GUIDrawTypeNames[] = {
"button",
"button pressed",
"sunken pane",
"window",
0
};
struct GUIPanel : public IGUIElement
{
GUIPanel( IGUIEnvironment* environment, IGUIElement* parent, const core::recti& position, s32 id=-1 );
void setDrawBackground( bool yes );
void setBackgroundType( EGUIDrawType );
void draw();
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "panel"; }
void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
protected:
bool DrawBackground;
EGUIDrawType BackgroundType;
video::SColor BackgroundColor;
bool DrawTitleBar; // Only applies when drawing as as Window
video::SColor TitleBarColor;
};
}
}
#endif

View File

@ -0,0 +1,593 @@
// (c) 2014 Nicolaus Anderson
#ifndef GUISCOLORSELECT_CPP
#define GUISCOLORSELECT_CPP
#include "GUISColorSelect.h"
#include <IGUIEnvironment.h>
#include <IVideoDriver.h>
namespace irr {
namespace gui {
using core::clamp;
using core::vector2d;
using core::floor32;
using core::ceil32;
using core::dimension2d;
using video::IVideoDriver;
GUISColorSelect::GUISColorSelect( IGUIEnvironment* pEnvironment, IGUIElement* pParent, recti pRect, s32 id )
: IGUISColorSelect( pEnvironment, pParent, pRect, id )
, color(SOLID_BLACK) // solid black for HSL constructor
, fieldAlpha(0)
, HUE_RANGE( 360.f )
, LUMINANCE_RANGE( 100.f )
, SATURATION_RANGE( 100.f )
, lastEvent( EGSCSE_None )
, mouseStateFlags(0)
, colorFieldRect(
vector2di(padding),
pRect.getSize() - dimension2d<s32>(2*padding, 30 + 2*padding)
)
, hueFieldRect(
vector2di(padding, pRect.getHeight()-30+(2*padding)),
vector2di(pRect.getWidth()-padding, pRect.getHeight()-padding)
)
, firstMousePos(0)
, startHue(0)
, lastColorFieldMousePos(0)
{
colorFieldRect.repair();
hueFieldRect.repair();
updateHueFieldRectangles();
}
SColor GUISColorSelect::getColor()
{
SColorf outf;
color.toRGB(outf);
return outf.toSColor();
}
SColor GUISColorSelect::getHueAsColor()
{
SColorHSL outHSL(color.Hue, SATURATION_RANGE, LUMINANCE_RANGE);
SColorf outf;
outHSL.toRGB(outf);
return outf.toSColor();
}
void GUISColorSelect::setColor( SColor pColor, bool notifyParent )
{
SColorf cf(pColor);
color.fromRGB(cf);
fieldAlpha = u8(pColor.getAlpha());
// Calculate color coordinates for the last color-field mouse position
lastColorFieldMousePos.X =
colorFieldRect.LowerRightCorner.X
- (s32)( (color.Saturation / SATURATION_RANGE) * (f32)(colorFieldRect.getWidth()-1.f) );
lastColorFieldMousePos.Y =
colorFieldRect.LowerRightCorner.Y
- (s32) ( (color.Luminance / LUMINANCE_RANGE) * (f32)(colorFieldRect.getHeight()-1) );
// Notify parent
if ( Parent && notifyParent )
sendGUIEvent(EGET_EDITBOX_CHANGED);
}
void GUISColorSelect::setHue( SColor pColor, bool notifyParent )
{
SColorf cf( pColor );
SColorHSL chsl;
chsl.fromRGB(cf);
color.Hue = chsl.Hue;
if ( Parent && notifyParent )
sendGUIEvent(EGET_EDITBOX_CHANGED);
}
void GUISColorSelect::setAlpha( u8 pAlpha )
{
fieldAlpha = pAlpha;
}
void GUISColorSelect::updateAbsolutePosition()
{
IGUIElement::updateAbsolutePosition();
colorFieldRect.UpperLeftCorner.set(padding,padding);
colorFieldRect.LowerRightCorner.set(
vector2di(RelativeRect.getSize()) - vector2di(padding,30+2*padding)
);
hueFieldRect.UpperLeftCorner.set( padding, RelativeRect.getHeight()-30+(2*padding) );
hueFieldRect.LowerRightCorner.set(
RelativeRect.getWidth()-padding,
RelativeRect.getHeight()-padding
);
updateHueFieldRectangles();
}
EGUISColorSelectEvent GUISColorSelect::getEvent()
{
return lastEvent;
}
bool GUISColorSelect::OnEvent( const SEvent& event )
{
if ( isEnabled() && isVisible() )
switch ( event.EventType )
{
case EET_MOUSE_INPUT_EVENT:
return onMouseEvent(event);
case EET_KEY_INPUT_EVENT:
return onKeyEvent(event);
default: break;
}
return IGUIElement::OnEvent(event);
}
bool GUISColorSelect::onMouseEvent( const SEvent& event )
{
vector2di lastMousePos( event.MouseInput.X, event.MouseInput.Y );
/* Note: this GUI Element may respond even when not in focus.
However, forcing it to respond when in focus forces the user to
click on it, which can cause the color values to change, messing
up the value. */
switch ( event.MouseInput.Event )
{
case EMIE_LMOUSE_PRESSED_DOWN:
setMouseState( MOUSE_LEFT_PRESSED, true );
/* Check to see if the mouse is in the correct areas
for modifying the color. */
if ( colorFieldRect.isPointInside( lastMousePos - AbsoluteRect.UpperLeftCorner ) )
{
setMouseState( MOUSE_IN_COLOR_FIELD );
}
else if ( hueFieldRect.isPointInside( lastMousePos - AbsoluteRect.UpperLeftCorner ) )
{
setMouseState( MOUSE_IN_HUE_FIELD );
}
return true;
case EMIE_LMOUSE_LEFT_UP:
if ( getMouseState( MOUSE_LEFT_PRESSED ) )
{
resetMouseState( MOUSE_LEFT_PRESSED );
resetMouseState( MOUSE_IN_COLOR_FIELD );
resetMouseState( MOUSE_IN_HUE_FIELD );
sendGUIEvent(EGET_EDITBOX_CHANGED);
}
return true;
case EMIE_MMOUSE_PRESSED_DOWN:
setMouseState( MOUSE_MIDDLE_PRESSED, true );
firstMousePos = lastMousePos;
startHue = color.Hue;
return true;
case EMIE_MMOUSE_LEFT_UP:
resetMouseState( MOUSE_MIDDLE_PRESSED );
sendGUIEvent(EGET_EDITBOX_CHANGED);
return true;
case EMIE_MOUSE_MOVED:
if ( getMouseState( MOUSE_LEFT_PRESSED ) )
{
if ( getMouseState( MOUSE_IN_COLOR_FIELD ) )
{
setColorFieldFromPosition( lastMousePos - AbsoluteRect.UpperLeftCorner );
sendGUIEvent(EGET_EDITBOX_CHANGED);
}
else if ( getMouseState( MOUSE_IN_HUE_FIELD ) )
{
setHueFieldFromPosition(
(lastMousePos - AbsoluteRect.UpperLeftCorner - padding).X
);
sendGUIEvent(EGET_EDITBOX_CHANGED);
}
return true; // absorb anyways
}
else if ( getMouseState( MOUSE_MIDDLE_PRESSED ) )
{
// Change the hue and update the hue bar
setHueFieldFromShift( lastMousePos.X - firstMousePos.X );
sendGUIEvent(EGET_EDITBOX_CHANGED);
return true;
}
return false;
default: break;
}
return false;
}
void GUISColorSelect::sendGUIEvent( EGUI_EVENT_TYPE pEventType, IGUIElement* pElement )
{
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = pElement;
event.GUIEvent.EventType = pEventType;
if ( Parent )
Parent->OnEvent(event);
}
bool GUISColorSelect::onKeyEvent( const SEvent& event )
{
switch ( event.KeyInput.Key )
{
case KEY_KEY_R:
setColor( SOLID_RED );
return true;
case KEY_KEY_Y:
setColor( SOLID_YELLOW );
return true;
case KEY_KEY_G:
setColor( SOLID_GREEN );
return true;
case KEY_KEY_T:
setColor( SOLID_TEAL );
return true;
case KEY_KEY_B:
setColor( SOLID_BLUE );
return true;
case KEY_KEY_P:
setColor( SOLID_PURPLE );
return true;
default: break;
}
return false;
}
void GUISColorSelect::setMouseState( c8 pState, bool pResetOthers )
{
if ( !pResetOthers )
{
mouseStateFlags |= pState;
return;
}
mouseStateFlags = pState;
}
void GUISColorSelect::resetMouseState( c8 pState )
{
mouseStateFlags &= ~pState;
}
bool GUISColorSelect::getMouseState( c8 pState )
{
return (mouseStateFlags & pState) == pState;
}
void GUISColorSelect::setColorFieldFromPosition( vector2di pPos )
{
lastColorFieldMousePos = pPos;
/* NOTE: Padding to the left has already been accounted for. */
/* Move the position until it is in the field. */
lastColorFieldMousePos.X = clamp( pPos.X,
colorFieldRect.UpperLeftCorner.X,
colorFieldRect.LowerRightCorner.X );
lastColorFieldMousePos.Y = clamp( pPos.Y,
colorFieldRect.UpperLeftCorner.Y,
colorFieldRect.LowerRightCorner.Y );
/* Color field appearance:
white -------------------- white
| |
| |
full sat color unsaturated color
| |
| |
black -------------------- black
Meaning that the x position correlates with saturation
and the y position correlates with lightness.
*/
f32 sat = SATURATION_RANGE * (
(f32)((colorFieldRect.LowerRightCorner.X) - lastColorFieldMousePos.X)
/ (f32)(colorFieldRect.getWidth()-1)
);
f32 lum = LUMINANCE_RANGE * (
(f32)((colorFieldRect.LowerRightCorner.Y) - lastColorFieldMousePos.Y)
/ (f32)(colorFieldRect.getHeight()-1)
);
color.Saturation = clamp( sat, 0.f, SATURATION_RANGE );
color.Luminance = clamp( lum, 0.f, LUMINANCE_RANGE );
}
//=============================
// Wrong: It sets the color along the diagonal
// Preserved for reference
//void GUISColorSelect::setColorFieldFromPosition( vector2di pPos )
//{
// lastColorFieldMousePos = pPos;
//
// /* NOTE: Padding to the left has already been accounted for. */
// /* Move the position until it is in the field. */
// pPos.X = min_(
// colorFieldRect.LowerRightCorner.X,
// max_( colorFieldRect.UpperLeftCorner.X, pPos.X )
// );
// pPos.Y = min_(
// colorFieldRect.LowerRightCorner.Y,
// max_( colorFieldRect.UpperLeftCorner.Y, pPos.Y )
// );
//
// /* Color field appearance:
// full sat color ----------- white
// | |
// | |
// | |
// | |
// | |
// black -------------- unsaturated color
//
// Note: (0,0) is the upper left corner, meaning the fully saturated
// color lies on the rectangle's diagonal [(0,0),(w,h)] and the black
// and white lies on the diagonal [(0,h),(w,0)]
// */
//
// vector2d<f32> pos(pPos); // useful cast
//
// /* Lightness depends only on the projection of the vector
// onto the black-white diagonal. */
// vector2di bw(0-colorFieldRect.getWidth(), colorFieldRect.getHeight()-0);
// vector2d<f32> bw_f(bw);
// f32 bw_length = bw_f.getLength();
// f32 bw_projection = pos.dotProduct( bw_f.normalize() );
//
// color.Luminance = (bw_projection / bw_length) * LUMINANCE_RANGE;
//
// /* Saturation depends on the diagonal [(w,0),(0,h)] */
// vector2di sat(colorFieldRect.getWidth(), colorFieldRect.getHeight());
// vector2d<f32> sat_f(sat);
// f32 sat_length = sat_f.getLength();
// f32 sat_projection = pos.dotProduct( sat_f.normalize() );
//
// // 1 - projection because progression along the diagonal is toward unsaturated
// color.Saturation = (1.0f - sat_projection) * SATURATION_RANGE;
//}
void GUISColorSelect::setHueFieldFromPosition( s32 x )
{
if ( x < 0 )
x = 0;
if ( x >= hueFieldRect.getWidth() )
x = hueFieldRect.getWidth() - 1;
/* NOTE: Padding to the left has already been accounted for. */
f32 i = f32(x) * HUE_RANGE/(f32)(hueFieldRect.getWidth()-1);
color.Hue = clamp( i, 0.f, HUE_RANGE );
}
void GUISColorSelect::setHueFieldFromShift( s32 x )
{
color.Hue = startHue + (f32)x;
// cancel overshoots
while ( color.Hue < 0 )
{
color.Hue += HUE_RANGE;
}
while ( color.Hue >= HUE_RANGE )
{
color.Hue -= HUE_RANGE;
}
}
void GUISColorSelect::updateHueFieldRectangles()
{
f32 spacing = hueFieldRect.getWidth() / 6.f;
/* Spacing, in terms of hue, is 60, but there are six color segments
over a space of the hue field rectangle width.
red = 0
yellow = 60
green = 120
teal = 180
blue = 240
purple = 300
red top = 360
*/
redYellowRect = recti(0, 0, s32(spacing), hueFieldRect.getHeight()),
yellowGreenRect = recti(s32(spacing), 0, s32(spacing*2), hueFieldRect.getHeight()),
greenTealRect = recti(s32(spacing*2), 0, s32(spacing*3), hueFieldRect.getHeight()),
tealBlueRect = recti(s32(spacing*3), 0, s32(spacing*4), hueFieldRect.getHeight()),
bluePurpleRect = recti(s32(spacing*4), 0, s32(spacing*5), hueFieldRect.getHeight()),
purpleRedRect = recti(s32(spacing*5), 0, s32(spacing*6), hueFieldRect.getHeight());
redYellowRect += AbsoluteRect.UpperLeftCorner + hueFieldRect.UpperLeftCorner;
yellowGreenRect += AbsoluteRect.UpperLeftCorner + hueFieldRect.UpperLeftCorner;
greenTealRect += AbsoluteRect.UpperLeftCorner + hueFieldRect.UpperLeftCorner;
tealBlueRect += AbsoluteRect.UpperLeftCorner + hueFieldRect.UpperLeftCorner;
bluePurpleRect += AbsoluteRect.UpperLeftCorner + hueFieldRect.UpperLeftCorner;
purpleRedRect += AbsoluteRect.UpperLeftCorner + hueFieldRect.UpperLeftCorner;
}
void GUISColorSelect::draw()
{
if ( !isVisible() )
return;
IGUISkin* skin = Environment->getSkin();
// Draw color field border ----- (5-pixel padding is for this border)
recti colorFieldBorder(
vector2di(0),
colorFieldRect.getSize() + dimension2d<s32>(2*padding, 2*padding)
);
// move to absolute location
colorFieldBorder += AbsoluteRect.UpperLeftCorner;
// draw
skin->draw3DButtonPaneStandard(this, colorFieldBorder, &AbsoluteClippingRect);
// Draw color field ---------
SColorf fieldColorf;
SColorHSL hsl = color;
hsl.Luminance = 50;
hsl.Saturation = 100;
hsl.toRGB( fieldColorf );
recti colorFieldRectAbs = colorFieldRect + AbsoluteRect.UpperLeftCorner;
recti colorFieldRectAbs2 = colorFieldRectAbs;
colorFieldRectAbs2.UpperLeftCorner.Y += colorFieldRect.getHeight()/2;
colorFieldRectAbs.LowerRightCorner.Y = colorFieldRectAbs2.UpperLeftCorner.Y;
/* Problem: Burning's isn't coloring the rectangles correctly, so
to fix this, I need to change either
a) Burnings (a hassle) or
b) Create images that I draw myself (slow for drawing and chews resources) */
// top rectangle
Environment->getVideoDriver()->draw2DRectangle(
colorFieldRectAbs,
SOLID_WHITE, SOLID_WHITE, fieldColorf.toSColor(), SOLID_GREY,
&AbsoluteClippingRect
);
// bottom rectangle
Environment->getVideoDriver()->draw2DRectangle(
colorFieldRectAbs2,
fieldColorf.toSColor(), SOLID_GREY, SOLID_BLACK, SOLID_BLACK,
&AbsoluteClippingRect
);
// should be ((SOLID_BLACK & 0x00ffffff) | (fieldAlpha<<24 & 0xff000000))
// TO DO!!
/* ^ Note above, the current problem is that there is no checkered pattern
in the background in the case of transparent values. Furthermore, there is
no handling of transparent values. That's on the to-do list.
*/
// Draw the color tracker -------
recti colorTrackerRect(
lastColorFieldMousePos - vector2di(2),
lastColorFieldMousePos + vector2di(2)
);
// move to absolute location
colorTrackerRect += AbsoluteRect.UpperLeftCorner;
// draw
Environment->getVideoDriver()->draw2DRectangleOutline( colorTrackerRect, SOLID_GREY );
// Draw hue field border ----- (5-pixel padding is for this border also)
recti hueFieldBorder(
hueFieldRect.UpperLeftCorner - vector2di(padding),
hueFieldRect.LowerRightCorner + vector2di(padding)
);
// move to absolute location
hueFieldBorder += AbsoluteRect.UpperLeftCorner;
// draw
skin->draw3DButtonPaneStandard(this, hueFieldBorder, &AbsoluteClippingRect);
// Draw hue field ----------
/* Note: While it would be nice to use createGradientTexture(),
the engine resizes textures to be squares, needlessly chewing up
memory. However, it might be faster on the processor and would
be more convenient for programming. */
Environment->getVideoDriver()->draw2DRectangle(
redYellowRect,
SOLID_RED, SOLID_YELLOW,
SOLID_RED, SOLID_YELLOW,
&AbsoluteClippingRect
);
Environment->getVideoDriver()->draw2DRectangle(
yellowGreenRect,
SOLID_YELLOW, SOLID_GREEN,
SOLID_YELLOW, SOLID_GREEN,
&AbsoluteClippingRect
);
Environment->getVideoDriver()->draw2DRectangle(
greenTealRect,
SOLID_GREEN, SOLID_TEAL,
SOLID_GREEN, SOLID_TEAL,
&AbsoluteClippingRect
);
Environment->getVideoDriver()->draw2DRectangle(
tealBlueRect,
SOLID_TEAL, SOLID_BLUE,
SOLID_TEAL, SOLID_BLUE,
&AbsoluteClippingRect
);
Environment->getVideoDriver()->draw2DRectangle(
bluePurpleRect,
SOLID_BLUE, SOLID_PURPLE,
SOLID_BLUE, SOLID_PURPLE,
&AbsoluteClippingRect
);
Environment->getVideoDriver()->draw2DRectangle(
purpleRedRect,
SOLID_PURPLE, SOLID_RED,
SOLID_PURPLE, SOLID_RED,
&AbsoluteClippingRect
);
// Draw the hue field bar ------
s32 hueBarX = (s32)( (f32)(hueFieldRect.getWidth()) * color.Hue / HUE_RANGE );
recti hueFieldBar( hueBarX - 2, -2, hueBarX + 2, hueFieldRect.getHeight() + 2 );
// Move to draw location
hueFieldBar += hueFieldRect.UpperLeftCorner + AbsoluteRect.UpperLeftCorner;
// draw
Environment->getVideoDriver()->draw2DRectangleOutline(
hueFieldBar, SOLID_GREY
);
}
void GUISColorSelect::serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options
)
{
IGUIElement::serializeAttributes(out,options);
out->addColor("Color", getColor());
}
void GUISColorSelect::deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options
)
{
IGUIElement::deserializeAttributes(in,options);
setColor(in->getAttributeAsColor("Color", getColor()));
}
}
}
#endif // #ifndef GUISCOLORSELECT_CPP

View File

@ -0,0 +1,132 @@
// (c) 2014 Nicolaus Anderson
#ifndef GUISCOLORSELECT_H
#define GUISCOLORSELECT_H
#include "IGUISColorSelect.h"
#include "../video/Colors.h"
/*
NOTE TO SELF:
If you create an alpha-bar, it should be either to the right of the
color field or directly below the hue bar.
I could have made this of sub-elements
- one for the color field, which
would be merely a selection field returning values between 0 and 1 along
whatever horizontal, vertical, or diagonal you wanted
- two sliders for the hue and alpha bars, noting that the background of a
slider need not be drawn (so I could draw a hue gradient below it),
in which the sliders limit the selected range as well as both respond to
the middle mouse movement (if in focus)
(While it might annoy the user, the middle mouse button + direction in
the same direction as the orientation of the slider would matter, allowing
the user to control both hue and alpha (if on different bars), but not
if both bars are oriented the same. This could be very problematic.)
This level of abstraction would allow me to more easily control how
all of the pieces are placed on the screen.
*/
namespace irr {
namespace gui {
using core::vector2di;
using core::recti;
using video::SColor;
using video::SColorf;
using video::SColorHSL;
class GUISColorSelect : public IGUISColorSelect
{
protected:
SColorHSL color;
u8 fieldAlpha;
const f32 HUE_RANGE;// = 360.f; // 60 between each color and 1st and last red
const f32 LUMINANCE_RANGE;// = 100.f;
const f32 SATURATION_RANGE;// = 100.f;
EGUISColorSelectEvent lastEvent;
u8 mouseStateFlags;
static const u8 MOUSE_LEFT_PRESSED = 1;
static const u8 MOUSE_MIDDLE_PRESSED = 2;
static const u8 MOUSE_RIGHT_PRESSED = 4;
/* Indicates the mouse at least WAS in
the color fields upon the start of the
click, even if not now. */
static const u8 MOUSE_IN_COLOR_FIELD = 8;
static const u8 MOUSE_IN_HUE_FIELD = 16;
private:
static const s32 padding = 5; // padding for the color field rectangles
recti colorFieldRect;
recti hueFieldRect;
vector2di firstMousePos;
f32 startHue;
vector2di lastColorFieldMousePos;
// color rectangles for the hue field
recti redYellowRect,
yellowGreenRect,
greenTealRect,
tealBlueRect,
bluePurpleRect,
purpleRedRect;
public:
GUISColorSelect( IGUIEnvironment* pEnvironment, IGUIElement* pParent, recti pRect, s32 id=-1 );
virtual SColor getColor();
SColor getHueAsColor();
void setColor( SColor pColor, bool notifyParent=true );
void setHue( SColor pColor, bool notifyParent=true );
void setAlpha( u8 pAlpha );
/* To do...
Add overrides for updating the Relative rectangle.
This can be done by overridding only updateAbsolutePosition() */
virtual void updateAbsolutePosition();
virtual EGUISColorSelectEvent getEvent();
virtual bool OnEvent( const SEvent& event );
private:
bool onMouseEvent( const SEvent& event );
void sendGUIEvent( EGUI_EVENT_TYPE pEventType, IGUIElement* pElement=0 );
bool onKeyEvent( const SEvent& event );
inline void setMouseState( c8 pState, bool pResetOthers=false );
inline void resetMouseState( c8 pState );
inline bool getMouseState( c8 pState );
void setColorFieldFromPosition( vector2di pPos );
void setHueFieldFromPosition( s32 x );
void setHueFieldFromShift( s32 x );
void updateHueFieldRectangles();
public:
virtual void draw();
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "sColorSelect"; }
virtual void serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options=0
);
virtual void deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options=0
);
};
}
}
#endif // #ifndef GUISCOLORSELECT_H

View File

@ -0,0 +1,71 @@
// (c) 2015 Nicolaus Anderson
#ifndef GUI_S_PROGRESS_BAR_H
#define GUI_S_PROGRESS_BAR_H
#include <IGUIElement.h>
#include <IGUISkin.h>
namespace irr {
namespace gui {
class GUISProgressBar : public IGUIElement
{
f32 value;
bool horiz;
video::SColor backColor;
public:
GUISProgressBar( IGUIEnvironment* pEnv, IGUIElement* pParent, core::recti pRect, s32 id=-1,
f32 pStartValue=0, bool pHorizontal=true )
: IGUIElement( EGUIET_ELEMENT, pEnv, pParent, id, pRect )
, value( pStartValue )
, horiz( pHorizontal )
, backColor( 0xff222222 )
{}
void setProgress( f32 pPercent )
{
value = pPercent;
}
void setBackgroundColor( video::SColor pBackColor )
{
backColor = pBackColor;
}
virtual void draw()
{
Environment->getSkin()->draw3DSunkenPane(this, backColor, true, true, AbsoluteRect, &AbsoluteClippingRect );
core::recti bar(AbsoluteRect);
if ( horiz )
{
bar.LowerRightCorner.X = AbsoluteRect.UpperLeftCorner.X + (s32)(value * RelativeRect.getWidth());
} else {
bar.LowerRightCorner.Y = AbsoluteRect.UpperLeftCorner.Y + (s32)(value * RelativeRect.getHeight());
}
Environment->getSkin()->draw3DButtonPaneStandard(this, bar, &AbsoluteClippingRect);
}
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "sProgressBar"; }
virtual void serializeAttributes( irr::io::IAttributes* out, irr::io::SAttributeReadWriteOptions* options )
{
IGUIElement::serializeAttributes(out,options);
out->addFloat("Progress", value);
out->addColor("BackgroundColor", backColor);
}
virtual void deserializeAttributes( irr::io::IAttributes* in, irr::io::SAttributeReadWriteOptions* options )
{
IGUIElement::serializeAttributes(in,options);
setProgress( in->getAttributeAsFloat("Progress",value) );
setBackgroundColor( in->getAttributeAsColor("BackgroundColor") );
}
};
}}
#endif // #ifndef GUI_S_PROGRESS_BAR_H

View File

@ -0,0 +1,258 @@
// Copyright 2016 Nic Anderson
#include "GUIScrollPane.h"
#include <IGUIScrollBar.h>
#include <IGUIEnvironment.h>
namespace irr {
namespace gui {
GUIScrollPane::GUIScrollPane( IGUIEnvironment* pGUIEnvironment, IGUIElement* pParent, recti pRect, irr::s32 id )
: IGUIElement( EGUIET_ELEMENT, pGUIEnvironment, pParent, id, pRect )
, horizontalScrollBar(0)
, verticalScrollBar(0)
, barWidth(20)
, childWrapper(0)
{
constructChildWrapper(pGUIEnvironment, pRect);
recti r = recti(0, pRect.getHeight()-barWidth, pRect.getWidth(), pRect.getHeight());
horizontalScrollBar = pGUIEnvironment->addScrollBar(true, r, this);
horizontalScrollBar->setAlignment(EGUIA_UPPERLEFT,EGUIA_LOWERRIGHT,EGUIA_LOWERRIGHT,EGUIA_LOWERRIGHT);
horizontalScrollBar->setSubElement(true);
horizontalScrollBar->setSmallStep(5);
horizontalScrollBar->setLargeStep(20);
horizontalScrollBar->setPos(0);
r = recti(pRect.getWidth()-barWidth, 0, pRect.getWidth(), pRect.getHeight()-barWidth);
verticalScrollBar = pGUIEnvironment->addScrollBar(false, r, this);
verticalScrollBar->setAlignment(EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT);
verticalScrollBar->setSubElement(true);
verticalScrollBar->setSmallStep(5);
verticalScrollBar->setLargeStep(20);
verticalScrollBar->setPos(0);
}
GUIScrollPane::~GUIScrollPane()
{
/* if ( horizontalScrollBar )
horizontalScrollBar->drop();
if ( verticalScrollBar )
verticalScrollBar->drop();*/
}
void GUIScrollPane::constructChildWrapper(IGUIEnvironment* pGUIEnvironment, recti position)
{
recti r = position;
r.LowerRightCorner.X -= barWidth;
r.LowerRightCorner.Y -= barWidth;
childWrapper = new IGUIElement( EGUIET_ELEMENT, pGUIEnvironment, this, -1, r );
childWrapper->drop(); // This element will handle the reference counting
childWrapper->setTabGroup(true);
}
IGUIElement* GUIScrollPane::getChildWrapper() const
{
return childWrapper;
}
void GUIScrollPane::showHorizontalScrollBar(bool yes)
{
recti r;
if ( yes && horizontalScrollBar->isVisible() == false )
{
r = childWrapper->getRelativePosition();
r.LowerRightCorner.X -= barWidth;
childWrapper->setRelativePosition(r);
r = verticalScrollBar->getRelativePosition();
r.LowerRightCorner.Y -= barWidth;
verticalScrollBar->setRelativePosition(r);
} else if ( !yes && horizontalScrollBar->isVisible() ) {
r = childWrapper->getRelativePosition();
r.LowerRightCorner.X += barWidth;
childWrapper->setRelativePosition(r);
r = verticalScrollBar->getRelativePosition();
r.LowerRightCorner.Y += barWidth;
verticalScrollBar->setRelativePosition(r);
}
horizontalScrollBar->setVisible(yes);
horizontalScrollBar->setEnabled(yes);
recalculateChildBounds();
}
void GUIScrollPane::showVerticalScrollBar(bool yes)
{
recti r;
if ( yes && verticalScrollBar->isVisible() == false )
{
r = childWrapper->getRelativePosition();
r.LowerRightCorner.Y -= barWidth;
childWrapper->setRelativePosition(r);
} else if ( !yes && verticalScrollBar->isVisible() ) {
r = childWrapper->getRelativePosition();
r.LowerRightCorner.Y += barWidth;
childWrapper->setRelativePosition(r);
}
verticalScrollBar->setVisible(yes);
verticalScrollBar->setEnabled(yes);
recalculateChildBounds();
}
IGUIScrollBar* GUIScrollPane::getHorizontalBar() const
{
return horizontalScrollBar;
}
IGUIScrollBar* GUIScrollPane::getVerticalBar() const
{
return verticalScrollBar;
}
void GUIScrollPane::setRelativePosition( recti pPosition )
{
IGUIElement::setRelativePosition(pPosition);
updateAbsolutePosition();
}
void GUIScrollPane::addChild( IGUIElement* pElement )
{
// IGUIElement::addChild(pElement);
childWrapper->addChild(pElement);
childWrapper->updateAbsolutePosition();
childStartPositions.push_back(
GUIElementPosition( pElement, pElement->getRelativePosition().UpperLeftCorner )
);
recalculateChildBounds();
// Should I have added an offset? Chat clients would not benefit from it but other programs would.
}
void GUIScrollPane::removeChild( IGUIElement* pElement )
{
u32 index = 0;
for ( ; index < childStartPositions.size(); index++ )
{
if ( childStartPositions[index].element == pElement )
{
childStartPositions.erase(index);
break;
}
}
childWrapper->removeChild(pElement);
recalculateChildBounds();
}
void GUIScrollPane::clearChildren()
{
core::list<IGUIElement*>::ConstIterator kid = childWrapper->getChildren().begin();
while ( kid != childWrapper->getChildren().end() ) {
childWrapper->removeChild(*kid);
kid = childWrapper->getChildren().begin();
}
}
void GUIScrollPane::updateAbsolutePosition()
{
IGUIElement::updateAbsolutePosition();
recalculateChildBounds();
}
bool GUIScrollPane::OnEvent(const SEvent& event)
{
if ( !IsEnabled )
return false;
switch ( event.EventType )
{
case EET_MOUSE_INPUT_EVENT:
break;
case EET_KEY_INPUT_EVENT:
// Scroll on arrow keys?
// Remember to set the scroll bars and get the position from them
break;
case EET_GUI_EVENT:
if ( event.GUIEvent.EventType == EGET_SCROLL_BAR_CHANGED )
{
shiftChildrenToPosition(
horizontalScrollBar->getPos(),
verticalScrollBar->getPos()
);
}
break;
default: break;
}
return IGUIElement::OnEvent( event );
}
void
GUIScrollPane::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const {
IGUIElement::serializeAttributes(out, options);
out->addBool("ShowHorizontalBar", horizontalScrollBar->isVisible() );
out->addBool("ShowVerticalBar", verticalScrollBar->isVisible() );
}
void
GUIScrollPane::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) {
IGUIElement::deserializeAttributes(in, options);
showHorizontalScrollBar( in->getAttributeAsBool("ShowHorizontalBar", horizontalScrollBar->isVisible()) );
showVerticalScrollBar( in->getAttributeAsBool("ShowVerticalBar", verticalScrollBar->isVisible()) );
}
void GUIScrollPane::recalculateChildBounds()
{
if ( childWrapper->getChildren().size() == 0 ) {
childBounds = core::rect<s32>();
return;
}
core::list<IGUIElement*>::ConstIterator iter = childWrapper->getChildren().begin();
childBounds = (*iter)->getRelativePosition();
core::rect<s32> bound;
for ( ; iter != childWrapper->getChildren().end(); ++iter )
{
bound = (*iter)->getRelativePosition();
childBounds.addInternalPoint( bound.UpperLeftCorner );
childBounds.addInternalPoint( bound.LowerRightCorner );
}
// Update the scroll bars
horizontalScrollBar->setMax( childBounds.getWidth() );
verticalScrollBar->setMax( childBounds.getHeight() );
}
void GUIScrollPane::shiftChildrenToPosition( s32 x, s32 y )
{
if ( childWrapper->getChildren().size() == 0 )
return;
// Since all children shift the same, only one start position is needed to find the shift
core::list<IGUIElement*>::ConstIterator iter = childWrapper->getChildren().begin();
core::rect<s32> bound = (*iter)->getRelativePosition();
u32 i=0;
core::vector2d<s32> startPos,
currShift,
newShift;
for ( ; i < childStartPositions.size(); ++i )
{
if ( childStartPositions[i].element == *iter )
{
startPos = childStartPositions[i].position;
break;
}
}
currShift = startPos - bound.UpperLeftCorner;
//newShift.set( currShift.X - x, currShift.Y - y ); // TODO: Uncomment and comment out the next line?? What was wrong?
newShift.set( 0, currShift.Y - y );
for ( ; iter != childWrapper->getChildren().end(); ++iter )
{
(*iter)->move(newShift);
}
}
}}

View File

@ -0,0 +1,66 @@
// Copyright 2016 Nic Anderson
#ifndef GUIScrollPane_H
#define GUIScrollPane_H
#include <IGUIElement.h>
namespace irr {
namespace gui {
class IGUIScrollBar;
using irr::core::recti;
class GUIScrollPane : public IGUIElement
{
protected:
struct GUIElementPosition
{
IGUIElement* element;
core::vector2d<s32> position;
GUIElementPosition( IGUIElement* e, core::vector2d<s32> p )
: element(e), position(p)
{}
};
IGUIScrollBar* horizontalScrollBar;
IGUIScrollBar* verticalScrollBar;
u32 barWidth; // Width of a scroll width across its short side
IGUIElement* childWrapper;
core::array<GUIElementPosition> childStartPositions; // (not in same order as Children)
core::rect<s32> childBounds; // rectangle around all children
public:
GUIScrollPane( IGUIEnvironment* pGUIEnvironment, IGUIElement* pParent, recti pRect, irr::s32 id=-1 );
~GUIScrollPane();
void constructChildWrapper(IGUIEnvironment* pGUIEnvironment, recti position);
IGUIElement* getChildWrapper() const;
void showHorizontalScrollBar(bool yes);
void showVerticalScrollBar(bool yes);
IGUIScrollBar* getHorizontalBar() const;
IGUIScrollBar* getVerticalBar() const;
virtual void setRelativePosition( recti pPosition );
virtual void addChild( IGUIElement* pElement );
virtual void removeChild( IGUIElement* pElement );
void clearChildren();
virtual void updateAbsolutePosition();
virtual bool OnEvent(const SEvent& event);
virtual void serializeAttributes(io::IAttributes*, io::SAttributeReadWriteOptions*) const;
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "scrollPane"; }
protected:
void recalculateChildBounds();
void shiftChildrenToPosition( s32 x, s32 y );
};
}}
#endif

View File

@ -0,0 +1,156 @@
// (c) 2015 Nicolaus Anderson
/*
TODO: This may be removed in the future!
*/
#ifndef GUI_TEXTURE_H
#define GUI_TEXTURE_H
#include <irrString.h>
#include <IGUIElement.h>
//#include <ITexture.h>
#include <IVideoDriver.h>
namespace irr {
namespace gui {
using core::recti;
using core::stringc;
using video::ITexture;
using video::IRenderTarget;
using video::IVideoDriver;
// GUI element for displaying a texture, one that can be rendered to as a render target.
class GUITextureView : public IGUIElement
{
ITexture* texture;
ITexture* depthStencil;
IRenderTarget* renderTarget;
io::path internalName;
bool useAlphaChannel;
bool removeTexturesOnDestroy;
public:
// Texture-display version (no IImage version at the moment)
GUITextureView( ITexture* pTexture, IGUIEnvironment* pEnv, IGUIElement* pParent, recti pRect, s32 id=-1, bool pRemoveTexturesOnDestroy=true )
: IGUIElement( EGUIET_ELEMENT, pEnv, pParent, id, pRect )
, texture( pTexture )
, depthStencil(0)
, renderTarget(0)
, useAlphaChannel(false)
, removeTexturesOnDestroy(pRemoveTexturesOnDestroy)
{
internalName = io::path(stringc("GUI_TEXTURE_") + stringc(id));
}
~GUITextureView()
{
IVideoDriver* videoDriver = Environment->getVideoDriver();
if ( renderTarget )
videoDriver->removeRenderTarget( renderTarget );
if ( removeTexturesOnDestroy )
{
videoDriver->removeTexture( texture );
videoDriver->removeTexture( depthStencil );
}
}
//! Set the texture
/* Sets the texture displayed by this GUI element.
Note: It is the responsibility of the programmer to ensure this texture is removed when
no longer needed. */
void setTexture( ITexture* pTexture )
{
texture = pTexture;
}
ITexture* getTexture()
{
return texture;
}
/*
// Commented out until I know how the depth stencil works
void setDepthStencil( ITexture* pDepthStencil )
{
depthStencil = pDepthStencil;
}
*/
void setUseAlphaChannelOnDraw( bool yes )
{
useAlphaChannel = yes;
}
//! Get the render target
/* Creates and returns a render target.
Note: This will erase the pointer to any existing texture, so it is important
that you remove the texture yourself prior to calling this function. */
IRenderTarget* getRenderTarget( bool pUseCurrentTargetSize=true ) // core::dimension2du pOverrideSize = core::dimension2du() )
{
IVideoDriver* videoDriver;
dimension2du targetSize;
if ( !renderTarget )
{
AbsoluteRect.repair(); // Ensure it is positive
videoDriver = Environment->getVideoDriver();
// Using the AbsoluteRect size could be problematic since the texture size must be both:
// 1) Equal to or smaller than the screen size (since it shares the z-buffer) AND
// 2) A power of 2 in both width and height (which the screen size might not be)
if ( pUseCurrentTargetSize )
targetSize = videoDriver->getCurrentRenderTargetSize();
else
targetSize = dimension2du( AbsoluteRect.getSize() );
texture = videoDriver->addRenderTargetTexture( targetSize, internalName, video::ECF_A8R8G8B8 );
depthStencil = videoDriver->addRenderTargetTexture( targetSize, internalName + "Depth", video::ECF_G16R16F );
// ^ What color format should the stencil buffer be for OpenGL? A8R8G8B8?
// User named Entity uses ECF_G16R16F, but I suppose it doesn't matter as long as its 32-bits.
renderTarget = videoDriver->addRenderTarget();
renderTarget->setTexture(texture, depthStencil);
}
return renderTarget;
}
void removeRenderTarget()
{
if ( renderTarget )
{
Environment->getVideoDriver()->removeRenderTarget(renderTarget);
renderTarget = 0;
}
}
void setUseAlphaChannel( bool yes )
{
useAlphaChannel = yes;
}
virtual void draw()
{
if ( !texture ) return;
recti sourceRect( texture->getOriginalSize() );
if ( isVisible() && isEnabled() )
{
//Environment->getVideoDriver()->draw2DRectangle( video::SColor(0xffff0000), AbsoluteRect, &AbsoluteClippingRect );
// Yes, it is drawing, but the background is black, even though the lighting is working.
Environment->getVideoDriver()->draw2DImage( texture, AbsoluteRect.UpperLeftCorner,
sourceRect, &AbsoluteClippingRect,
video::SColor(0xffffffff), useAlphaChannel );
}
}
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "textureView"; }
// TODO: Serialization
};
}}
#endif // #ifndef GUI_TEXTURE_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,289 @@
// (c) 2014 Nic Anderson
#ifndef GUITREETABLE_H
#define GUITREETABLE_H
#include <IGUIElement.h>
#include "../util/irrTree/irrTree.h"
#include <IGUIWindow.h>
/* Compile option: _COMPILE_GUI_TREE_TABLE_NICE_
Creates a gradient-background, but does not allow the skin
to control the drawing of the background.
It is also costly for rendering.
*/
namespace irr {
namespace gui {
using irr::core::clamp;
using irr::core::list;
using irr::core::vector2di;
using irr::core::recti;
enum EGUITreeTableActivity
{
// No activity
EGTTABLEA_None,
/* When the user uses their middle mouse button, they can move all of
the windows. However, they are not allowed to do other activities. */
EGTTABLEA_Scroll,
/* When a context menu is open, the user's mouse is monitored for
whether or not the menu is closed. When the context menu is in use,
other activities (such as node linking) cannot be done. However, those
activites can be a consequence of using the menu.
Since the context menu can close itself, this is used only
to indicate if the activity should be monitored.
If removed, the buttons of this menu will not be
clickable. However, I will have to either
a) reconstruct the menu every time (takes time)
b) remove the main table GUI from being the parent until it is needed,
which means I have to monitor the GUI event of the context menu losing
focus, which shouldn't be too hard. */
EGTTABLEA_UsingContextMenu,
/* When a user has clicked a node and chosen to make it the parent
of the next selected node. Note that, in order to make this succeed,
the soon-to-be-child must be delinked from any previous parent. */
EGTTABLEA_LinkingNodeToChild,
/* When a user has clicked a node and chosen to make it the child
of the next selected node. Note that, in order to make this succeed,
the child must be delinked from any previous parent. */
EGTTABLEA_LinkingNodeToParent,
/* When a user has clicked a node and chosen to separate it from its
child. Then the child must be selected. */
EGTTABLEA_BreakFromChild,
/* When the user decides to disconnect this node from its parent node.
NOTE: This action occurs immediately and therefore does not exist as
a regular action but is listed here for reference. */
//EGTTABLEA_BreakFromParent,
// Number of activities
EGTTABLEA_COUNT
};
enum EGUITreeTableNodeMenuCommandId
{
// Add a new node to the list
EGTTABLE_NMCI_Add=0,
// Delete the selected node
EGTTABLE_NMCI_Delete,
// Duplicate the selected node
EGTTABLE_NMCI_Duplicate,
// Link the selected node to a child
EGTTABLE_NMCI_LinkToChild,
// Link the selected node to a parent
EGTTABLE_NMCI_LinkToParent,
// Break link from the selected node to a selected child
EGTTABLE_NMCI_BreakFromChild,
// Break link from the selected node to its parent and vice versa
EGTTABLE_NMCI_BreakFromParent,
// Make this node the root node
EGTTABLE_NMCI_MakeRoot,
// Number of nodes
EGTTABLE_NMCI_COUNT
};
/* The GUI event states, which can be checked with
GUITreeTable::getLastEventState(), and that way, we never
have to worry about extending EGUI_EVENT_TYPE for this
generic element. */
enum EGUITreeTableEvent
{
EGTTE_None,
EGTTE_SelectNode,
EGTTE_NoSelectNode, // No node selected (or current selection deselected)
//EGTTE_MoveNodes, // Not used - it would slow things down
EGTTE_OpenNodeMenu,
EGTTE_AddNode,
EGTTE_DuplicateNode,
EGTTE_RemoveNode,
EGTTE_LinkToChild,
EGTTE_LinkToParent,
EGTTE_BreakFromChild,
EGTTE_BreakFromParent,
EGTTE_PreMakeRoot,
EGTTE_PostMakeRoot,
EGTTE_COUNT
};
/* Class GUI Tree Table Element Factory
Inherit this class and pass it to GUITreeTable to allow for creating
the nodes that go in the tree table.
*/
class GUITreeTableElementFactory
{
public:
/* Meant for the user to take the window in the tree table and
modify it as they please, returning the tree element that is
represented by the window. */
virtual irrTreeElement* buildElementOfWindow( IGUIWindow* pWindow )=0;
/* Meant for duplicating the given tree element, especially
when 1) there is no copy-constructor for the element or
2) the programmer does not want the element to be directy copied. */
virtual irrTreeElement* buildElementDuplicateOf( irrTreeElement* pElement )=0;
/* Meant for when duplicating the selected node.
If something extra needs to be done to the duplicate (or something needs
to be updated concerning it), it can be done via this function.
\param pWindow - The window of the duplicate node. */
virtual void amendDuplicateWindow( IGUIWindow* pWindow )=0;
};
/* Class GUI Tree Table Node
Contains a pointer to the node itself and to the window representing it. */
class GUITreeTableNode
{
IGUIWindow* window;
irrTreeNode* node;
public:
GUITreeTableNode( IGUIWindow* pWindow, irrTreeNode* pNode );
GUITreeTableNode( const GUITreeTableNode& pOther );
~GUITreeTableNode();
IGUIWindow* getWindow();
irrTreeNode* getTreeNode();
irrTreeElement* getTreeNodeElement();
void setWindow( IGUIWindow* pWindow );
void setTreeNode( irrTreeNode* pNode );
void setTreeNodeElem( irrTreeElement* pElement );
bool isAncestorOf( GUITreeTableNode* pNode );
bool operator== ( const GUITreeTableNode& other );
};
/* Class GUI Tree Table
This class is a table containing a tree and a list of nodes.
All of the nodes are in the list, including the root (which cannot be
deleted), but, with the exception of the root, none of the nodes need
to be in the tree.
The table is merely a control for a bunch of windows that compose the
tree. These windows can be used by the user to connect or disconnect
the tree. The windows also contain whatever the user wants.
*/
class GUITreeTable : public IGUIElement
{
list<GUITreeTableNode> nodeList;
irrTreeNode* treeRoot;
GUITreeTableElementFactory* elementFactory;
vector2di lastMousePos, firstMousePos;
GUITreeTableNode* selectedNode;
IGUIContextMenu* nodeMenu;
EGUITreeTableActivity activity;
EGUITreeTableEvent lastEvent;
bool focusOnHover;
bool allowLinkingToParent;
bool canSelectedNodeLoseFocus;
s32 lineThickness;
recti nodeWindowSize;
irr::video::SColor
linkColor1,
linkColor2,
selectedHighlightColor;
#ifdef _COMPILE_GUI_TREE_TABLE_NICE_
irr::video::SColor backgroundColor2;
#endif
public:
GUITreeTable( IGUIEnvironment* pEnvironment,
IGUIElement* pParent,
recti pRect, s32 id=-1 );
~GUITreeTable();
/* Add a node at the last mouse location.
\param pElement - The element to be contained in this node.
\return - Window of the new node. */
IGUIWindow* addNode( irrTreeElement* pElement=0 );
void removeSelectedNode();
void removeNodeWithTreeElem( irrTreeElement* pElement );
/* Duplicate the selected node and add the duplicate at the last mouse location.
\param pElement - The element to be contained in this node.
\return - Window of the new node. */
IGUIWindow* duplicateSelectedNode();
void clearAll(bool pClearWindows=true); // kills everything
void clearAllTrees(); // no clearList() because then all would have to die
void setElementFactory( GUITreeTableElementFactory* pFactory );
void setFocusOnHover( bool pFocus ); // (sets the Environment focus to this when hovering over it)
void setLinkLineThickness( s32 pThickness );
void setNodeWindowRect( recti pRect );
recti getNodeWindowRect();
void setLinkColor1( irr::video::SColor pColor );
void setLinkColor2( irr::video::SColor pColor );
void setSelectedHighlightColor( irr::video::SColor pColor );
EGUITreeTableEvent getLastEventState();
IGUIWindow* getSelectedNodeWindow();
GUITreeTableNode* getSelectedNode();
GUITreeTableNode* getTreeRootNode();
/* Set the tree root by giving the node. */
void setTreeRootNode( GUITreeTableNode& pNewRoot );
void setTreeRoot( irrTreeNode* pNewRoot );
list<GUITreeTableNode>& getNodeList();
protected:
IGUIContextMenu* getNodeMenu( bool pUpdatePosition=false );
inline void hideNodeMenu();
public:
virtual bool OnEvent( const SEvent& event );
bool sendMenuEvent( EGUITreeTableNodeMenuCommandId pCommand );
protected:
void sendEvent();
public:
virtual void draw();
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "treeTable"; }
protected:
GUITreeTableNode* findListNodeWithTreeNode( irrTreeNode* pNode );
void drawLink( IGUIElement* pFromElement, IGUIElement* pToElement );
bool handleMouseEvent( const SEvent& event );
bool handleKeyEvent( const SEvent& event );
bool handleGuiEvent( const SEvent& event );
GUITreeTableNode* getNodeAt( vector2di pPos );
GUITreeTableNode* getNodeWithWindow( IGUIWindow* pWindow );
//u32 getSelectedNodeIndex();
void selectNodeAt( vector2di pPos );
void selectNodeWithWindow( IGUIWindow* pWindow );
public:
void moveChildrenBy( vector2di pDistance );
recti getEnclosingRect(); // Relative (to parent) rectangle that wraps around all node windows
};
}}
#endif

View File

@ -0,0 +1,248 @@
// (c) 2015 Nicolaus Anderson
#ifndef GUI_VECTOR_PANEL_CPP
#define GUI_VECTOR_PANEL_CPP
#include "GUIVectorPanel.h"
#include <IGUISpinBox.h>
#include <IGUIEnvironment.h>
namespace irr {
namespace gui {
GUIVectorPanel::GUIVectorPanel( IGUIEnvironment* pEnvironment, IGUIElement* pParent, rect<s32> pRect, bool pEdit3D, s32 id )
: IGUIElement( EGUIET_ELEMENT, pEnvironment, pParent, id, pRect )
, X(0)
, Y(0)
, Z(0)
, edit3D( pEdit3D )
, dirtyRect( false )
, xEdit( 0 )
, yEdit( 0 )
, zEdit( 0 )
{
s32 coordBoxWidth;
s32 pad = 5;
if ( edit3D )
{
coordBoxWidth = (pRect.getWidth() - 2*pad) / 3;
} else {
coordBoxWidth = (pRect.getWidth() - pad) / 2;
}
rect<s32> valueRect( 0, 0, coordBoxWidth, pRect.getHeight() );
core::vector2di valueRectShift( coordBoxWidth + pad, 0 );
xEdit = pEnvironment->addSpinBox( L"0.0", valueRect, true, this );
xEdit->setAlignment( EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT );
xEdit->setStepSize(0.1f);
xEdit->setValidateOn(EGUI_SBV_CHANGE); // Requirement for irrlicht 1.9 to update on any change to the spin box
//valueRect.move( coordBoxWidth + pad, 0 ); // custom Irrlicht
valueRect.UpperLeftCorner += valueRectShift;
valueRect.LowerRightCorner += valueRectShift;
yEdit = pEnvironment->addSpinBox( L"0.0", valueRect, true, this );
yEdit->setAlignment( EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT );
yEdit->setStepSize(0.1f);
yEdit->setValidateOn(EGUI_SBV_CHANGE); // Requirement for irrlicht 1.9 to update on any change to the spin box
//valueRect.move( coordBoxWidth + pad, 0 ); // custom Irrlicht
valueRect.UpperLeftCorner += valueRectShift;
valueRect.LowerRightCorner += valueRectShift;
zEdit = pEnvironment->addSpinBox( L"0.0", valueRect, true, this );
zEdit->setAlignment( EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT );
zEdit->setStepSize(0.1f);
zEdit->setValidateOn(EGUI_SBV_CHANGE); // Requirement for irrlicht 1.9 to update on any change to the spin box
if ( ! edit3D )
{
zEdit->setVisible(false);
}
}
void GUIVectorPanel::set2DValue( f32 pX, f32 pY )
{
X = pX;
Y = pY;
xEdit->setValue( X );
yEdit->setValue( Y );
}
void GUIVectorPanel::set2DVectorValue( vector2d<f32> pValue )
{
X = pValue.X;
Y = pValue.Y;
xEdit->setValue( X );
yEdit->setValue( Y );
}
void GUIVectorPanel::set3DValue( f32 pX, f32 pY, f32 pZ )
{
X = pX;
Y = pY;
Z = pZ;
xEdit->setValue( X );
yEdit->setValue( Y );
zEdit->setValue( Z );
}
void GUIVectorPanel::set3DVectorValue( vector3d<f32> pValue )
{
X = pValue.X;
Y = pValue.Y;
Z = pValue.Z;
xEdit->setValue( X );
yEdit->setValue( Y );
zEdit->setValue( Z );
}
void GUIVectorPanel::reset()
{
X = 0;
Y = 0;
Z = 0;
xEdit->setValue( X );
yEdit->setValue( Y );
zEdit->setValue( Z );
}
void GUIVectorPanel::setEdit2DVector() // Force editing a 2D vector
{
edit3D = false;
dirtyRect = true;
updateAbsolutePosition();
}
void GUIVectorPanel::setEdit3DVector() // Force editing a 3D vector
{
edit3D = true;
dirtyRect = true;
updateAbsolutePosition();
}
bool GUIVectorPanel::isEditing3D()
{
return edit3D;
}
vector2d<f32> GUIVectorPanel::getVector2D()
{
return vector2d<f32>( X, Y );
}
vector3d<f32> GUIVectorPanel::getVector3D()
{
return vector3d<f32>( X, Y, Z );
}
void GUIVectorPanel::updateAbsolutePosition()
{
// Needs to be fixed?
s32 coordBoxScale;
f32 fpad = 5.0f / (f32) RelativeRect.getWidth();
if ( dirtyRect )
{
if ( edit3D )
{
coordBoxScale = 1.f/3.f - fpad*2;
} else {
coordBoxScale = 0.5f - fpad;
}
rect<f32> valueRect( 0, 0, coordBoxScale, 1.0f );
xEdit->setRelativePositionProportional( valueRect );
core::vector2df valueRectShift( coordBoxScale + fpad, 0.f );
//valueRect.move( coordBoxScale + fpad, 0.f ); // custom Irrlicht
valueRect.UpperLeftCorner += valueRectShift;
valueRect.LowerRightCorner += valueRectShift;
yEdit->setRelativePositionProportional( valueRect );
if ( edit3D )
{
//valueRect.move( coordBoxScale + fpad, 0.f ); // custom Irrlicht
valueRect.UpperLeftCorner += valueRectShift;
valueRect.LowerRightCorner += valueRectShift;
zEdit->setRelativePositionProportional( valueRect );
} else {
zEdit->setVisible(false);
}
dirtyRect = false;
}
IGUIElement::updateAbsolutePosition();
}
bool GUIVectorPanel::OnEvent( const SEvent& event )
{
if ( !isVisible() || !isEnabled() || event.EventType != EET_GUI_EVENT )
return false;
if ( event.GUIEvent.Caller == xEdit )
{
X = xEdit->getValue();
sendGUIEvent( EGET_EDITBOX_CHANGED, xEdit );
return true;
}
else if ( event.GUIEvent.Caller == yEdit )
{
Y = yEdit->getValue();
sendGUIEvent( EGET_EDITBOX_CHANGED, yEdit );
return true;
}
else if ( event.GUIEvent.Caller == zEdit )
{
Z = zEdit->getValue();
sendGUIEvent( EGET_EDITBOX_CHANGED, zEdit );
return true;
}
return false;
}
void GUIVectorPanel::sendGUIEvent( EGUI_EVENT_TYPE pEventType, IGUIElement* pElement )
{
if ( ! Parent ) return;
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = pElement;
event.GUIEvent.EventType = pEventType;
Parent->OnEvent(event);
}
void GUIVectorPanel::serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options
)
{
IGUIElement::serializeAttributes(out,options);
out->addBool("Edit3D", edit3D);
out->addFloat("X", X);
out->addFloat("Y", X);
out->addFloat("Z", X);
}
void GUIVectorPanel::deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options
)
{
IGUIElement::deserializeAttributes(in,options);
edit3D = in->getAttributeAsBool("Edit3D", edit3D);
if ( edit3D )
setEdit3DVector();
else
setEdit2DVector();
X = in->getAttributeAsFloat("X");
Y = in->getAttributeAsFloat("Y");
Z = in->getAttributeAsFloat("Z");
}
}}
#endif // #ifndef GUI_VECTOR_PANEL_CPP

View File

@ -0,0 +1,72 @@
// (c) 2015 Nicolaus Anderson
#ifndef GUI_VECTOR_PANEL_H
#define GUI_VECTOR_PANEL_H
#include <vector3d.h>
#include <IGUIElement.h>
namespace irr {
namespace gui {
using core::vector2d;
using core::vector3d;
using core::rect;
class IGUISpinBox;
//! GUI Vector Panel
/* This class is a GUI element that contains three edit-boxes (spin boxes, at the moment) for modifying a vector.
Optionally, this class can edit a 3D vector instead of a 2D one. */
class GUIVectorPanel : public IGUIElement
{
// Dimensions
f32 X, Y, Z;
bool edit3D;
bool dirtyRect;
IGUISpinBox* xEdit;
IGUISpinBox* yEdit;
IGUISpinBox* zEdit;
public:
GUIVectorPanel( IGUIEnvironment* pEnvironment, IGUIElement* pParent, rect<s32> pRect, bool pEdit3D=false, s32 id=-1 );
void set2DValue( f32 pX, f32 pY );
void set2DVectorValue( vector2d<f32> pValue );
void set3DValue( f32 pX, f32 pY, f32 pZ );
void set3DVectorValue( vector3d<f32> pValue );
void reset();
/* Set editing a vector.
DO NOT CHANGE! In the future, this may be set to allowing editing 4D vectors. */
void setEdit2DVector(); // Force editing a 2D vector
void setEdit3DVector(); // Force editing a 3D vector
bool isEditing3D();
vector2d<f32> getVector2D();
vector3d<f32> getVector3D();
virtual void updateAbsolutePosition(); // changes the sizes of the child elements
virtual bool OnEvent( const SEvent& event );
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "vectorPanel"; }
virtual void serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options=0
);
virtual void deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options=0
);
private:
void sendGUIEvent( EGUI_EVENT_TYPE pEventType, IGUIElement* pElement );
};
}}
#endif // #ifndef GUI_VECTOR_PANEL_H

View File

@ -0,0 +1,413 @@
/* Taken from the irrlicht engine
and slightly modified by adding
an event parent and changing names.
Modifications by Nic Anderson. */
#ifndef _GUIWINDOW2_CPP_
#define _GUIWINDOW2_CPP_
#include "GUIWindow2.h"
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIButton.h"
#include "IGUIFont.h"
#include "IGUIFontBitmap.h"
namespace irr
{
namespace gui
{
//! constructor
GUIWindow2::GUIWindow2( IGUIEnvironment* pEnvironment, IGUIElement* pParent, rect<s32> pRect, s32 id )
: IGUIWindow(pEnvironment, pParent, id, pRect)
, CloseButton(0)
, MinButton(0)
, RestoreButton(0)
, ClientRect()
, CurrentIconColor()
, EventParent(0)
, Dragging(false)
, IsDraggable(true)
, DrawBackground(true)
, DrawTitlebar(true)
, IsActive(false)
{
#ifdef _DEBUG
setDebugName("GUIWindow2");
#endif
IGUISkin* skin = 0;
if (Environment)
skin = Environment->getSkin();
CurrentIconColor = video::SColor(255,255,255,255);
s32 buttonw = 15;
if (skin)
{
buttonw = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH);
}
s32 posx = RelativeRect.getWidth() - buttonw - 4;
CloseButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw), this, -1,
L"", skin ? skin->getDefaultText(EGDT_WINDOW_CLOSE) : L"Close" );
CloseButton->setSubElement(true);
CloseButton->setTabStop(false);
CloseButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
posx -= buttonw + 2;
RestoreButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw), this, -1,
L"", skin ? skin->getDefaultText(EGDT_WINDOW_RESTORE) : L"Restore" );
RestoreButton->setVisible(false);
RestoreButton->setSubElement(true);
RestoreButton->setTabStop(false);
RestoreButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
posx -= buttonw + 2;
MinButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw), this, -1,
L"", skin ? skin->getDefaultText(EGDT_WINDOW_MINIMIZE) : L"Minimize" );
MinButton->setVisible(false);
MinButton->setSubElement(true);
MinButton->setTabStop(false);
MinButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
MinButton->grab();
RestoreButton->grab();
CloseButton->grab();
// this element is a tab group
setTabGroup(true);
setTabStop(true);
setTabOrder(-1);
refreshSprites();
updateClientRect();
}
//! destructor
GUIWindow2::~GUIWindow2()
{
if (MinButton)
MinButton->drop();
if (RestoreButton)
RestoreButton->drop();
if (CloseButton)
CloseButton->drop();
}
void GUIWindow2::refreshSprites()
{
if (!Environment)
return;
IGUISkin* skin = Environment->getSkin();
if ( !skin )
return;
IGUISpriteBank* sprites = skin->getSpriteBank();
if ( !sprites )
return;
CurrentIconColor = skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL);
if (sprites)
{
CloseButton->setSpriteBank(sprites);
CloseButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_CLOSE), CurrentIconColor);
CloseButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_CLOSE), CurrentIconColor);
RestoreButton->setSpriteBank(sprites);
RestoreButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_RESTORE), CurrentIconColor);
RestoreButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_RESTORE), CurrentIconColor);
MinButton->setSpriteBank(sprites);
MinButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_MINIMIZE), CurrentIconColor);
MinButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_MINIMIZE), CurrentIconColor);
}
}
//! called if an event happened.
bool GUIWindow2::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_GUI_EVENT:
/* Note that this only handles GUI events. Mouse events for child elements
are not handled because focus is determined by the environment. */
if ( event.GUIEvent.Caller != this )
if ( EventParent )
if ( EventParent->OnEvent(event) )
return true;
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
{
Dragging = false;
IsActive = false;
if ( EventParent )
EventParent->OnEvent(event);
}
else
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)
{
if (Parent && ((event.GUIEvent.Caller == this) || isMyChild(event.GUIEvent.Caller)))
{
Parent->bringToFront(this);
IsActive = true;
if ( EventParent )
EventParent->OnEvent(event);
}
else
{
IsActive = false;
}
}
else
if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED)
{
if (event.GUIEvent.Caller == CloseButton)
{
if ( EventParent )
{
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = this;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_ELEMENT_CLOSED;
// event parent may catch this event
if ( EventParent->OnEvent(e) )
return true;
}
if (Parent)
{
// send close event to parent
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = this;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_ELEMENT_CLOSED;
// if the event was not absorbed
if (!Parent->OnEvent(e))
remove();
return true;
}
else
{
remove();
return true;
}
}
}
break;
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event)
{
case EMIE_LMOUSE_PRESSED_DOWN:
DragStart.X = event.MouseInput.X;
DragStart.Y = event.MouseInput.Y;
Dragging = IsDraggable;
if (Parent)
Parent->bringToFront(this);
return true;
case EMIE_LMOUSE_LEFT_UP:
Dragging = false;
return true;
case EMIE_MOUSE_MOVED:
if (!event.MouseInput.isLeftPressed())
Dragging = false;
if (Dragging)
{
// gui window should not be dragged outside its parent
if (Parent &&
(event.MouseInput.X < Parent->getAbsolutePosition().UpperLeftCorner.X +1 ||
event.MouseInput.Y < Parent->getAbsolutePosition().UpperLeftCorner.Y +1 ||
event.MouseInput.X > Parent->getAbsolutePosition().LowerRightCorner.X -1 ||
event.MouseInput.Y > Parent->getAbsolutePosition().LowerRightCorner.Y -1))
return true;
move(core::position2d<s32>(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y));
DragStart.X = event.MouseInput.X;
DragStart.Y = event.MouseInput.Y;
return true;
}
break;
default:
break;
}
default:
break;
}
}
if ( EventParent )
if ( EventParent->OnEvent(event) )
return true;
return IGUIElement::OnEvent(event);
}
//! set event parent
/* Nic Anderson mod */
void GUIWindow2::setEventParent( IEventReceiver* pEventParent )
{
EventParent = pEventParent;
}
//! Updates the absolute position.
void GUIWindow2::updateAbsolutePosition()
{
IGUIElement::updateAbsolutePosition();
}
//! draws the element and its children
void GUIWindow2::draw()
{
if (IsVisible)
{
IGUISkin* skin = Environment->getSkin();
// update each time because the skin is allowed to change this always.
updateClientRect();
if ( CurrentIconColor != skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL) )
refreshSprites();
core::rect<s32> rect = AbsoluteRect;
// draw body fast
if (DrawBackground)
{
rect = skin->draw3DWindowBackground(this, DrawTitlebar,
skin->getColor(IsActive ? EGDC_ACTIVE_BORDER : EGDC_INACTIVE_BORDER),
AbsoluteRect, &AbsoluteClippingRect);
if (DrawTitlebar && Text.size())
{
rect.UpperLeftCorner.X += skin->getSize(EGDS_TITLEBARTEXT_DISTANCE_X);
rect.UpperLeftCorner.Y += skin->getSize(EGDS_TITLEBARTEXT_DISTANCE_Y);
rect.LowerRightCorner.X -= skin->getSize(EGDS_WINDOW_BUTTON_WIDTH) + 5;
IGUIFont* font = skin->getFont(EGDF_WINDOW);
if (font)
{
font->draw(Text.c_str(), rect,
skin->getColor(IsActive ? EGDC_ACTIVE_CAPTION:EGDC_INACTIVE_CAPTION),
false, true, &AbsoluteClippingRect);
}
}
}
}
IGUIElement::draw();
}
//! Returns pointer to the close button
IGUIButton* GUIWindow2::getCloseButton() const
{
return CloseButton;
}
//! Returns pointer to the minimize button
IGUIButton* GUIWindow2::getMinimizeButton() const
{
return MinButton;
}
//! Returns pointer to the maximize button
IGUIButton* GUIWindow2::getMaximizeButton() const
{
return RestoreButton;
}
//! Returns true if the window is draggable, false if not
bool GUIWindow2::isDraggable() const
{
return IsDraggable;
}
//! Sets whether the window is draggable
void GUIWindow2::setDraggable(bool draggable)
{
IsDraggable = draggable;
if (Dragging && !IsDraggable)
Dragging = false;
}
//! Set if the window background will be drawn
void GUIWindow2::setDrawBackground(bool draw)
{
DrawBackground = draw;
}
//! Get if the window background will be drawn
bool GUIWindow2::getDrawBackground() const
{
return DrawBackground;
}
//! Set if the window titlebar will be drawn
void GUIWindow2::setDrawTitlebar(bool draw)
{
DrawTitlebar = draw;
}
//! Get if the window titlebar will be drawn
bool GUIWindow2::getDrawTitlebar() const
{
return DrawTitlebar;
}
void GUIWindow2::updateClientRect()
{
if (! DrawBackground )
{
ClientRect = core::rect<s32>(0,0, AbsoluteRect.getWidth(), AbsoluteRect.getHeight());
return;
}
IGUISkin* skin = Environment->getSkin();
skin->draw3DWindowBackground(this, DrawTitlebar,
skin->getColor(IsActive ? EGDC_ACTIVE_BORDER : EGDC_INACTIVE_BORDER),
AbsoluteRect, &AbsoluteClippingRect, &ClientRect);
ClientRect -= AbsoluteRect.UpperLeftCorner;
}
//! Returns the rectangle of the drawable area (without border, without titlebar and without scrollbars)
core::rect<s32> GUIWindow2::getClientRect() const
{
return ClientRect;
}
} // end namespace gui
} // end namespace irr
#endif // #ifndef _GUIWINDOW2_CPP_

View File

@ -0,0 +1,89 @@
/* Taken from the irrlicht engine
and slightly modified by adding
an event parent and changing names.
Modifications by Nic Anderson. */
#ifndef _GUIWINDOW2_H_
#define _GUIWINDOW2_H_
#include <IGUIWindow.h>
namespace irr {
namespace gui {
using core::rect;
class GUIWindow2 : public IGUIWindow
{
public:
GUIWindow2( IGUIEnvironment* pEnvironment, IGUIElement* pParent, rect<s32> pRect, s32 id=-1 );
~GUIWindow2();
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! set event parent
/* Nic Anderson mod */
void setEventParent( IEventReceiver* pEventParent );
//! update absolute position
virtual void updateAbsolutePosition();
//! draws the element and its children
virtual void draw();
//! Returns pointer to the close button
virtual IGUIButton* getCloseButton() const;
//! Returns pointer to the minimize button
virtual IGUIButton* getMinimizeButton() const;
//! Returns pointer to the maximize button
virtual IGUIButton* getMaximizeButton() const;
//! Returns true if the window is draggable, false if not
virtual bool isDraggable() const;
//! Sets whether the window is draggable
virtual void setDraggable(bool draggable);
//! Set if the window background will be drawn
virtual void setDrawBackground(bool draw);
//! Get if the window background will be drawn
virtual bool getDrawBackground() const;
//! Set if the window titlebar will be drawn
//! Note: If the background is not drawn, then the titlebar is automatically also not drawn
virtual void setDrawTitlebar(bool draw);
//! Get if the window titlebar will be drawn
virtual bool getDrawTitlebar() const;
//! Returns the rectangle of the drawable area (without border and without titlebar)
virtual core::rect<s32> getClientRect() const;
protected:
void updateClientRect();
void refreshSprites();
IGUIButton* CloseButton;
IGUIButton* MinButton;
IGUIButton* RestoreButton;
core::rect<s32> ClientRect;
video::SColor CurrentIconColor;
IEventReceiver* EventParent; // Nic Anderson mod
core::position2d<s32> DragStart;
bool Dragging, IsDraggable;
bool DrawBackground;
bool DrawTitlebar;
bool IsActive;
};
}} // end namespaces
#endif // #ifndef _GUIWINDOW2_H_

View File

@ -0,0 +1,47 @@
// (c) 2014 Nicolaus Anderson
/* Color selection dialog. Notably, it allows selecting and returning
an SColor specifically (as opposed to other color types, such as SColorf.
This element should be able to be embedded in a window but does not need to be. */
#ifndef IGUISCOLORSELECT_H
#define IGUISCOLORSELECT_H
#include <SColor.h>
#include <IGUIElement.h>
namespace irr {
using core::recti;
using video::SColor;
namespace gui {
// For the window containing the color select dialog
enum EGUISColorSelectEvent
{
EGSCSE_None,
EGSCSE_ColorChanged,
EGSCSE_COUNT
};
class IGUISColorSelect : public IGUIElement
{
public:
IGUISColorSelect( IGUIEnvironment* pEnvironment, IGUIElement* pParent, recti pRect, s32 id=-1 )
: IGUIElement( EGUIET_ELEMENT, pEnvironment, pParent, id, pRect )
{}
//! Get the color
/* Returns the ARGB color of this dialog, regardless of if it stores HSV natively. */
virtual SColor getColor()=0;
//! Get event
/* Returns the event that occurs if, for example, the user interacts with it. */
virtual EGUISColorSelectEvent getEvent()=0;
};
}
}
#endif // #ifndef IGUISCOLORSELECT_H

View File

@ -0,0 +1,140 @@
// (C) 2020 Nicolaus Anderson
#include "IrrExtGUIElementFactory.h"
#include <ISceneManager.h>
// EXCLUDE: GUIWindow2
#include "SimpleGraph/SGraph2D.h"
#include "GUIColorEditBox.h"
#include "GUIColorSample.h"
#include "GUIDualSection.h"
#include "GUIDropdownSelector.h"
#include "GUIFileSelectPanel.h"
#include "GUIGroupingPanel.h"
#include "GUIMarkedSlider.h"
#include "GUIMaterialPanel.h"
#include "GUIMatrixPanel.h"
#include "GUISProgressBar.h"
#include "GUISColorSelect.h"
#include "GUIScrollPane.h"
#include "GUITextureView.h"
#include "GUITreeTable.h" // Requires irrTree: util/irrTree/irrTree/irrTree.h
#include "GUIVectorPanel.h"
namespace irr {
namespace gui {
IrrExtGUIElementFactory::IrrExtGUIElementFactory( IGUIEnvironment* environment, scene::ISceneManager* manager )
: Environment(environment)
, SceneManager(manager)
{}
IGUIElement*
IrrExtGUIElementFactory::addGUIElement(EGUI_ELEMENT_TYPE type, IGUIElement* parent) {
return 0;
}
IGUIElement*
IrrExtGUIElementFactory::addGUIElement(const c8* typeName, IGUIElement* parent) {
core::stringc elemname(typeName);
if ( elemname == SGraph2D::staticTypeName() ) {
return new SGraph2D( Environment, parent, -1, core::recti(), core::rectf(-1,-1,1,1) );
}
else if ( elemname == GUIColorEditBox::staticTypeName() ) {
return new GUIColorEditBox( Environment, parent, core::recti() );
}
else if ( elemname == GUIColorSample::staticTypeName() ) {
return new GUIColorSample( Environment, parent, core::recti() );
}
else if ( elemname == GUIDualSection::staticTypeName() ) {
// Default: horizontal/left-and-right sections
return new GUIDualSection( false, 0.5f, Environment, parent, core::recti() );
}
else if ( elemname == GUIDropdownSelector::staticTypeName() ) {
return new GUIDropdownSelector( Environment, parent, core::recti() );
}
else if ( elemname == GUIFileSelectPanel::staticTypeName() ) {
return new GUIFileSelectPanel( Environment, parent, core::recti(), "." );
}
else if ( elemname == GUIGroupingPanel::staticTypeName() ) {
/* Could be saved for elsewhere because we might want access to getClientArea().
Alternatively, add it to items set by serializeAttributes(). */
return new GUIGroupingPanel( L"", Environment, parent, core::recti() );
}
else if ( elemname == GUIMarkedSlider::staticTypeName() ) {
// Default: vertical
return new GUIMarkedSlider( true, 100, core::recti(), Environment, parent );
}
else if ( elemname == GUIMaterialPanel::staticTypeName() ) {
return new GUIMaterialPanel( Environment, SceneManager, parent, core::recti() );
}
else if ( elemname == GUIMatrixPanel::staticTypeName() ) {
// Default: rotate in degrees
return new GUIMatrixPanel( true, Environment, parent, core::recti() );
}
else if ( elemname == GUISProgressBar::staticTypeName() ) {
return new GUISProgressBar( Environment, parent, core::recti() );
}
else if ( elemname == GUISColorSelect::staticTypeName() ) {
return new GUISColorSelect( Environment, parent, core::recti() );
}
else if ( elemname == GUIScrollPane::staticTypeName() ) {
return new GUIScrollPane( Environment, parent, core::recti() );
}
else if ( elemname == GUITextureView::staticTypeName() ) {
// FIXME: GUITextureView requires a unique ID so it can give a unique name to render targets
static u32 i = 1; ++i;
return new GUITextureView(0, Environment, parent, core::recti(), i);
}
else if ( elemname == GUITreeTable::staticTypeName() ) {
return new GUITreeTable( Environment, parent, core::recti() );
}
else if ( elemname == GUIVectorPanel::staticTypeName() ) {
return new GUIVectorPanel( Environment, parent, core::recti() );
}
return 0;
}
s32
IrrExtGUIElementFactory::getCreatableGUIElementTypeCount() const {
return 16;
}
EGUI_ELEMENT_TYPE
IrrExtGUIElementFactory::getCreateableGUIElementType(s32 idx) const {
return EGUIET_ELEMENT;
}
const c8*
IrrExtGUIElementFactory::getCreateableGUIElementTypeName(s32 idx) const {
switch(idx)
{
case 0: return SGraph2D::staticTypeName();
case 1: return GUIColorEditBox::staticTypeName();
case 2: return GUIColorSample::staticTypeName();
case 3: return GUIDualSection::staticTypeName();
case 4: return GUIDropdownSelector::staticTypeName();
case 5: return GUIFileSelectPanel::staticTypeName();
case 6: return GUIGroupingPanel::staticTypeName();
case 7: return GUIMarkedSlider::staticTypeName();
case 8: return GUIMaterialPanel::staticTypeName();
case 9: return GUIMatrixPanel::staticTypeName();
case 10: return GUISProgressBar::staticTypeName();
case 11: return GUISColorSelect::staticTypeName();
case 12: return GUIScrollPane::staticTypeName();
case 13: return GUITextureView::staticTypeName();
case 14: return GUITreeTable::staticTypeName();
case 15: return GUIVectorPanel::staticTypeName();
default: return "";
}
}
const c8*
IrrExtGUIElementFactory::getCreateableGUIElementTypeName(EGUI_ELEMENT_TYPE type) const {
return "";
}
} // namespace gui
} // namespace irr

View File

@ -0,0 +1,41 @@
// (C) 2020 Nicolaus Anderson
#ifndef IRR_EXT_GUI_ELEMENT_FACTORY_H
#define IRR_EXT_GUI_ELEMENT_FACTORY_H
#include <IGUIElementFactory.h>
namespace irr {
namespace scene {
class ISceneManager;
}
namespace gui {
class IGUIElement;
class IGUIEnvironment;
//! IrrEXT GUI Element Factory
/*
Produces the GUI elements of the IrrExt project by chronologicaldot (Nic Anderson).
See Irrlicht file IGUIElementFactory.h for documentation.
*/
class IrrExtGUIElementFactory
: public irr::gui::IGUIElementFactory
{
IGUIEnvironment* Environment;
scene::ISceneManager* SceneManager;
public:
IrrExtGUIElementFactory( IGUIEnvironment*, scene::ISceneManager* );
virtual IGUIElement* addGUIElement(EGUI_ELEMENT_TYPE type, IGUIElement* parent=0);
virtual IGUIElement* addGUIElement(const c8* typeName, IGUIElement* parent=0);
virtual s32 getCreatableGUIElementTypeCount() const;
virtual EGUI_ELEMENT_TYPE getCreateableGUIElementType(s32 idx) const;
virtual const c8* getCreateableGUIElementTypeName(s32 idx) const;
virtual const c8* getCreateableGUIElementTypeName(EGUI_ELEMENT_TYPE type) const;
};
} // namespace gui
} // namespace irr
#endif // IRR_EXT_GUI_ELEMENT_FACTORY_H

View File

@ -0,0 +1,110 @@
/*
Simple Graph
(c) Nicolaus Anderson
Created Jan 7, 2013
License: Same terms as irrlicht
*/
#include <irrlicht.h>
#ifndef _IGRAPH2D_
#define _IGRAPH2D_
namespace irr
{
namespace gui
{
//! Class Graph 2D
/*
Purpose: To plot 2D math functions.
*/
class IGraph2D : public IGUIElement
{
public:
IGraph2D( IGUIEnvironment* envir, IGUIElement* parent, irr::s32 id, const irr::core::recti& rectangle )
: IGUIElement( EGUIET_ELEMENT, envir, parent, id, rectangle )
{
}
virtual ~IGraph2D()
{
}
//! Set graph size
/* NOT the same as scaling.
This function changes the ranges of values in the graph without changing
the size of the graph as a GUI element.
*/
virtual void setGraphSize( irr::core::rectf& size )=0;
//! Set graph size along one dimension
/* NOT the same as scaling.
This function changes the ranges of values of ONE AXIS in the graph without
changing the size of the graph as a GUI element.
\param size - New axis min or max
\param isMax - If the value given is for the maximum
*/
virtual void setGraphSizeX( irr::f32 size, bool isMax=true )=0;
virtual void setGraphSizeY( irr::f32 size, bool isMax=true )=0;
//! Set scale
/* Changes the scale of the ranges of values in the graph without changing
the size of the graph itself.
NOTE: Since this is a scaling, the rectangle being passed in should be the
percentage change (i.e. multiplier for the current values). */
virtual void setGraphScale( irr::core::rectf& scale )=0;
//! Get graph size
/* Returns the size of the graph. */
virtual irr::core::rectf getGraphSize()=0;
//! Draw
/* Draws the GUI element. */
virtual void draw()=0;
//! Clear graph
/* Erases everything in the graph. */
virtual void clearGraph()=0;
//-------------------------------
// Drawing area functions / Spaz
//! Set point color
/* Sets the color of the points to be displayed. */
virtual void setPointColor( irr::video::SColor color )=0;
//! Set x-axis color
/* Sets the color that will be used in drawing the line representing
the x-axis. */
virtual void setXAxisColor( irr::video::SColor color )=0;
//! Set y-axis color
/* Sets the color that will be used in drawing the line representing
the y-axis. */
virtual void setYAxisColor( irr::video::SColor color )=0;
//-----------------------------
//! Serialize attributes
virtual void serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options=0
)=0;
//! Deserialize attributes
virtual void deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options=0
)=0;
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "iGraph2D"; }
};
} // end namespace gui
} // end namespace irr
#endif // define _IGRAPH2D_

View File

@ -0,0 +1,912 @@
/*
Simple Graph
(c) Nicolaus Anderson
Created Jan 7, 2013
License: Same terms as irrlicht
*/
#include "SGraph2D.h"
#include <stdio.h>
#ifndef __SIMPLEGRAPH2D_CPP__
#define __SIMPLEGRAPH2D_CPP__
void irr::gui::SGraph2D::setGraphSize( irr::core::rectf& size )
{
// Change the points so they can be drawn correctly on the new window
changeGraphWindow( size );
ReallocateGraphSpace();
}
void irr::gui::SGraph2D::setGraphSizeX( irr::f32 size, bool isMax )
{
irr::core::rectf new_window(window);
// Note that LowerRightCorner is actually the top
if ( isMax )
{
new_window.LowerRightCorner.X = size;
} else {
new_window.UpperLeftCorner.X = size;
}
new_window.repair();
// Change the points so they can be drawn correctly on the new window
changeGraphWindow( new_window );
ReallocateGraphSpace();
}
void irr::gui::SGraph2D::setGraphSizeY( irr::f32 size, bool isMax )
{
irr::core::rectf new_window(window);
// Note that LowerRightCorner is actually the top
if ( isMax )
{
new_window.LowerRightCorner.Y = size;
} else {
new_window.UpperLeftCorner.Y = size;
}
new_window.repair();
// Change the points so they can be drawn correctly on the new window
changeGraphWindow( new_window );
ReallocateGraphSpace();
}
void irr::gui::SGraph2D::setGraphScale( irr::core::rectf& scale )
{
irr::core::rectf new_window(window);
new_window.UpperLeftCorner.X *= scale.UpperLeftCorner.X;
new_window.UpperLeftCorner.Y *= scale.UpperLeftCorner.Y;
new_window.LowerRightCorner.X *= scale.LowerRightCorner.X;
new_window.LowerRightCorner.Y *= scale.LowerRightCorner.Y;
new_window.repair();
// Change the points so they can be drawn correctly on the new window
changeGraphWindow( new_window );
ReallocateGraphSpace();
}
void irr::gui::SGraph2D::ReallocateGraphSpace()
{
graphImage.reallocate(
(irr::u32)AbsoluteRect.getWidth(),
false
);
}
void irr::gui::SGraph2D::changeGraphWindow( irr::core::rectf new_win )
{
irr::core::position2df point;
// Save the ratios - for convenience
irr::f32 winARx = window.getWidth() / (f32)AbsoluteRect.getWidth();
irr::f32 winARy = window.getHeight() / (f32)AbsoluteRect.getHeight();
irr::f32 ARnwinx = (f32)AbsoluteRect.getWidth() / new_win.getWidth();
irr::f32 ARnwiny = (f32)AbsoluteRect.getHeight() / new_win.getHeight();
// Restore all points with new values in the new window
for ( irr::u32 p=0; p < graphImage.size(); p++ )
{
point.X =
(
// shift from the old graph window (same as in first loop)
graphImage[p].Pos.X * winARx
+ window.UpperLeftCorner.X
-new_win.UpperLeftCorner.X // shift to new origin
)
* ARnwinx; // change to irrlicht coordinate scale
point.Y =
(
// shift from the old graph window (same as in first loop)
graphImage[p].Pos.Y * winARy
+ window.UpperLeftCorner.Y
-new_win.UpperLeftCorner.Y // shift to new origin
)
* ARnwiny; // change to irrlicht coordinate scale
// Overwrite the old point
graphImage[p].Pos.X = point.X;
graphImage[p].Pos.Y = point.Y;
}
// Overwrite the original window
window = new_win;
}
irr::core::rectf irr::gui::SGraph2D::getGraphSize()
{
return window;
}
Range<irr::f32> irr::gui::SGraph2D::getXAxisRange()
{
return Range<irr::f32>(
window.UpperLeftCorner.X,
window.LowerRightCorner.X
);
}
Range<irr::f32> irr::gui::SGraph2D::getYAxisRange()
{
return Range<irr::f32>(
window.UpperLeftCorner.Y,
window.LowerRightCorner.Y
);
}
Inc<irr::f32> irr::gui::SGraph2D::getIterableXRange()
{
Inc<irr::f32> inc(Inc<irr::f32>::CYC_REPEAT);
inc.setRange( getXAxisRange() );
inc.setStep( window.getWidth() / ((irr::f32)AbsoluteRect.getWidth()) );
inc.restart();
return inc;
}
Inc<irr::f32> irr::gui::SGraph2D::getIterableYRange()
{
Inc<irr::f32> inc(Inc<irr::f32>::CYC_REPEAT);
inc.setRange( getYAxisRange() );
inc.setStep( window.getHeight() / ((irr::f32)AbsoluteRect.getHeight()) );
inc.restart();
return inc;
}
void irr::gui::SGraph2D::markerSpacingX( irr::f32 gap )
{
markXgap = gap;
}
void irr::gui::SGraph2D::markerSpacingY( irr::f32 gap )
{
markYgap = gap;
}
void irr::gui::SGraph2D::draw()
{
// Don't bother doing anything if this isn't visible
if ( !IsVisible || AbsoluteRect.getArea() == 0 || window.getArea() == 0.0f )
return;
// variables...
irr::core::vector2di point; /* point to be drawn on screen representing
a point from the MathFunc */
/* Marker offset
- used to ensure the markers are drawn from the center outward. */
Inc<irr::f32> markerIter; /* no wrapping because we want
out-of-bounds checking */
// Marker line - drawn on the GUI graph screen
irr::core::line2df marker;
// For marker labels (drawn if desired)
irr::core::stringw label;
irr::core::position2df label_pos;
// operations...
// Draw the background if there is one
if ( hasBackground )
{
viddriver->draw2DRectangle(
background_color,
AbsoluteRect,
&AbsoluteClippingRect
);
}
// Draw the axis if desired
if ( showXaxis )
{
drawToGUI(
irr::core::line2df(
window.UpperLeftCorner.X,
0.0f,
window.LowerRightCorner.X,
0.0f
),
xaxis_color
);
}
if ( showYaxis )
{
drawToGUI(
irr::core::line2df(
0.0f,
window.UpperLeftCorner.Y,
0.0f,
window.LowerRightCorner.Y
),
yaxis_color
);
}
// Draw the markers/lines if desired
if ( UseMarkers )
{
// Y-axis
if ( showYaxisMarks )
{
/* Set the offset for making the lines appear to be drawn
from the center outward */
markerIter.setMin( window.UpperLeftCorner.Y );
markerIter.setMax( window.LowerRightCorner.Y );
markerIter.setStep( markYgap );
markerIter.setVal( 0.0f ); // start in the center
// Set up the marker line
// Left side of the line
if ( UseTicks )
marker.start.X = -window.getWidth() / 40.0f; // for 5% window width
else
marker.start.X = window.UpperLeftCorner.X;
// Right side of the line
if ( UseTicks )
marker.end.X = window.getWidth() / 40.0f; // for 5% window width
else
marker.end.X = window.LowerRightCorner.X;
// Draw each marker
while ( !++markerIter ) // go until past the max
{
// Assign the position to the line to draw
marker.start.Y = marker.end.Y = markerIter.Val();
// Draw the marker to the GUI
drawToGUI( marker, ymark_color );
// Write the axis value if desired
if ( UseYTickLabels )
{
label = irr::core::stringw( (irr::s32)markerIter.Val() );
label_pos.X = marker.end.X + window.getWidth()/50;
label_pos.Y = markerIter.Val();
drawToGUI( label, label_pos, ymark_color, false, true );
}
}
// Restart at the center
markerIter = 0.0f;
// Draw each marker
while ( !--markerIter ) // go until past the min
{
// Assign the position to the line to draw
marker.start.Y = markerIter.Val();
marker.end.Y = markerIter.Val();
// Draw the marker to the GUI
drawToGUI( marker, ymark_color );
// Write the axis value if desired
if ( UseYTickLabels )
{
label = irr::core::stringw( (irr::s32)markerIter.Val() );
label_pos.X = marker.end.X + window.getWidth()/50;
label_pos.Y = markerIter.Val();
drawToGUI( label, label_pos, ymark_color, false, true );
}
}
}
// X-axis
if ( showXaxisMarks )
{
/* Set the offset for making the lines appear to be drawn
from the center outward */
markerIter.setMin( window.UpperLeftCorner.X );
markerIter.setMax( window.LowerRightCorner.X );
markerIter.setStep( markXgap );
markerIter.setVal( 0.0f ); // start in the center
// Set up the marker line
// Top of the line - Below the x-axis in terms of irrlicht drawing
if ( UseTicks )
marker.start.Y = window.getHeight() / 40.0f; // for 5% window height
else
marker.start.Y = window.UpperLeftCorner.Y;
// Bottom of the line - Above the x-axis in terms of irrlicht drawing
if ( UseTicks )
marker.end.Y = -window.getHeight() / 40.0f; // for 5% window height
else
marker.end.Y = window.LowerRightCorner.Y;
// Draw each marker
while ( !++markerIter ) // go until past the max
{
// Assign the position to the line to draw
marker.start.X = marker.end.X = markerIter.Val();
// Draw the marker to the GUI
drawToGUI( marker, xmark_color );
// Write the axis value if desired
if ( UseXTickLabels )
{
label = irr::core::stringw( (irr::s32)markerIter.Val() );
label_pos.X = markerIter.Val();
label_pos.Y = marker.start.Y + window.getHeight()/50;
drawToGUI( label, label_pos, xmark_color, false, true );
}
}
// Restart at the center
markerIter = 0.0f;
// Draw each marker
while ( !--markerIter ) // go until past the min
{
// Assign the position to the line to draw
marker.start.X = markerIter.Val();
marker.end.X = markerIter.Val();
// Draw the marker to the GUI
drawToGUI( marker, xmark_color );
// Write the axis value if desired
if ( UseXTickLabels )
{
label = irr::core::stringw( (irr::s32)markerIter.Val() );
label_pos.X = markerIter.Val();
label_pos.Y = marker.start.Y + window.getHeight()/50;
drawToGUI( label, label_pos, xmark_color, false, true );
}
}
}
}
// Display each points on screen
for (
irr::s32 pt = 0;
pt < (irr::s32)graphImage.size();
pt++
)
{
point.X = (irr::s32)graphImage[pt].Pos.X;
point.Y = (irr::s32)graphImage[pt].Pos.Y;
drawToGUI( point, graphImage[pt].Color );
}
}
void irr::gui::SGraph2D::clearGraph()
{
graphImage.clear();
}
void irr::gui::SGraph2D::autoAdjust()
{
/* Since all of the data points were stored in irrlicht coordinates
system SCALE (in order to draw them faster) (NOT including offset)
they must be converted back to the graph window coordinate system
for the graph to be rescaled to fit them. This can be a costly operation,
(depending on the number of points saved to the graph) so this function
should be called only once - after all of the points have been added. */
/* Operations require that both windows - GUI and graph - exist,
otherwise we get a 1/0 errore
Furthermore, there must be points to graph. */
if ( window.getArea() == 0 || AbsoluteRect.getArea() == 0
|| graphImage.size() == 0 )
return;
// Temporary vertex for passing data
irr::core::position2df point;
// Temporary rectangle - for creating the new window
irr::core::rectf new_window;
// Save the ratios - for convenience
irr::f32 winARx = window.getWidth() / (f32)AbsoluteRect.getWidth();
irr::f32 winARy = window.getHeight() / (f32)AbsoluteRect.getHeight();
// First point determines start
/* This is done because the points may not actually reside anywhere
near the origin. */
new_window.UpperLeftCorner.X =
graphImage[0].Pos.X * winARx // change scale
+ window.UpperLeftCorner.X; // shift from corner to origin
new_window.LowerRightCorner.X =
graphImage[0].Pos.X * winARx // change scale
+ window.UpperLeftCorner.X; // shift from corner to origin
new_window.UpperLeftCorner.Y =
graphImage[0].Pos.Y * winARy // change scale
+ window.UpperLeftCorner.Y; // shift from corner to origin
new_window.LowerRightCorner.Y =
graphImage[0].Pos.Y * winARy // change scale
+ window.UpperLeftCorner.Y; // shift from corner to origin
// Generate the new window
for ( irr::u32 p=1; p < graphImage.size(); p++ )
{
point.X =
graphImage[p].Pos.X * winARx // change scale
+ window.UpperLeftCorner.X; // shift from corner to origin
point.Y =
graphImage[p].Pos.Y * winARy // change scale
+ window.UpperLeftCorner.Y; // shift from corner to origin
new_window.addInternalPoint( point );
}
changeGraphWindow( new_window );
}
void irr::gui::SGraph2D::setPointClipping( bool yes )
{
clipPoints = yes;
}
void irr::gui::SGraph2D::useBackground( bool use )
{
hasBackground = use;
}
void irr::gui::SGraph2D::setBackgroundColor( irr::video::SColor color )
{
background_color = color;
}
void irr::gui::SGraph2D::setPointColor( irr::video::SColor color )
{
point_color = color;
}
void irr::gui::SGraph2D::setXAxisColor( irr::video::SColor color )
{
xaxis_color = color;
}
void irr::gui::SGraph2D::setYAxisColor( irr::video::SColor color )
{
yaxis_color = color;
}
void irr::gui::SGraph2D::setShowXAxis( bool show )
{
showXaxis = show;
}
void irr::gui::SGraph2D::setShowYAxis( bool show )
{
showYaxis = show;
}
void irr::gui::SGraph2D::usePolygons( irr::f32 radius, irr::s32 corners )
{
usePolyPts = true;
polyRadius = radius;
polyPts = corners;
}
void irr::gui::SGraph2D::useNoPolygons()
{
usePolyPts = false;
}
void irr::gui::SGraph2D::showXAxisLabels( bool yes )
{
UseXTickLabels = yes;
}
void irr::gui::SGraph2D::showYAxisLabels( bool yes )
{
UseYTickLabels = yes;
}
void irr::gui::SGraph2D::useTicks()
{
UseMarkers = true;
UseTicks = true;
showXaxisMarks = true;
showYaxisMarks = true;
}
void irr::gui::SGraph2D::useLines()
{
UseMarkers = true;
UseTicks = false;
showXaxisMarks = true;
showYaxisMarks = true;
}
void irr::gui::SGraph2D::useNoMarkers()
{
UseMarkers = false;
}
void irr::gui::SGraph2D::showXAxisMarkers( bool show )
{
showXaxisMarks = show;
if (show) UseMarkers = true;
}
void irr::gui::SGraph2D::showYAxisMarkers( bool show )
{
showYaxisMarks = show;
if (show) UseMarkers = true;
}
void irr::gui::SGraph2D::setXAxisMarkerColor( irr::video::SColor color )
{
xmark_color = color;
}
void irr::gui::SGraph2D::setYAxisMarkerColor( irr::video::SColor color )
{
ymark_color = color;
}
void irr::gui::SGraph2D::serializeAttributes(
irr::io::IAttributes *out,
irr::io::SAttributeReadWriteOptions *options
)
{
IGUIElement::serializeAttributes( out, options );
irr::core::recti win;
win.UpperLeftCorner.X = (irr::s32)(window.UpperLeftCorner.X);
win.UpperLeftCorner.Y = (irr::s32)(window.UpperLeftCorner.Y);
win.LowerRightCorner.X = (irr::s32)(window.LowerRightCorner.X);
win.LowerRightCorner.Y = (irr::s32)(window.LowerRightCorner.Y);
out->addRect( "Window", win );
out->addBool( "FillBackground", hasBackground );
out->addColor( "BGColor", background_color );
out->addColor( "XAxisColor", xaxis_color );
out->addColor( "YAxisColor", yaxis_color );
out->addColor( "PointColor", point_color );
out->addColor( "XMarkColor", xmark_color );
out->addColor( "YMarkColor", ymark_color );
out->addColor( "XAxisTickColor", xmark_color );
out->addColor( "YAxisTickColor", ymark_color );
out->addBool( "UseMarkers", UseMarkers );
out->addBool( "UseTicks", UseTicks );
out->addFloat( "MarkerXSpacing", markXgap );
out->addFloat( "MarkerYSpacing", markYgap );
out->addBool( "ShowXAxisMarks", showXaxisMarks );
out->addBool( "ShowYAxisMarks", showYaxisMarks );
out->addBool( "ShowXAxis", showXaxis );
out->addBool( "ShowYAxis", showYaxis );
out->addBool( "ShowXAxisLabels", UseXTickLabels );
out->addBool( "ShowYAxisLabels", UseYTickLabels );
out->addBool( "ClipDrawingRegion", clipPoints );
out->addBool( "UsePolygons", usePolyPts );
out->addFloat( "PolygonRadius", polyRadius );
out->addInt( "PolygonVertices", polyPts );
}
void irr::gui::SGraph2D::deserializeAttributes(
irr::io::IAttributes *in,
irr::io::SAttributeReadWriteOptions *options
)
{
IGUIElement::deserializeAttributes( in, options );
irr::core::recti win;
irr::core::rectf winf;
if ( in->existsAttribute("Window") ) {
win = in->getAttributeAsRect( "Window" );
winf.UpperLeftCorner.X = (irr::f32)(win.UpperLeftCorner.X);
winf.UpperLeftCorner.Y = (irr::f32)(win.UpperLeftCorner.Y);
winf.LowerRightCorner.X = (irr::f32)(win.LowerRightCorner.X);
winf.LowerRightCorner.Y = (irr::f32)(win.LowerRightCorner.Y);
}
changeGraphWindow(winf);
hasBackground = in->getAttributeAsBool( "FillBackground", hasBackground );
background_color = in->getAttributeAsColor( "BGColor", background_color );
xaxis_color = in->getAttributeAsColor( "XAxisColor", xaxis_color );
yaxis_color = in->getAttributeAsColor( "YAxisColor", yaxis_color );
point_color = in->getAttributeAsColor( "PointColor", point_color );
xmark_color = in->getAttributeAsColor( "XMarkColor", xmark_color );
ymark_color = in->getAttributeAsColor( "YMarkColor", ymark_color );
xmark_color = in->getAttributeAsColor( "XAxisTickColor", xmark_color );
ymark_color = in->getAttributeAsColor( "YAxisTickColor", ymark_color );
UseMarkers = in->getAttributeAsBool( "UseMarkers", UseMarkers );
UseTicks = in->getAttributeAsBool( "UseTicks", UseTicks );
markXgap = in->getAttributeAsFloat( "MarkerXSpacing", markXgap );
markYgap = in->getAttributeAsFloat( "MarkerYSpacing", markXgap );
showXaxisMarks = in->getAttributeAsBool( "ShowXAxisMarks", showXaxisMarks );
showYaxisMarks = in->getAttributeAsBool( "ShowYAxisMarks", showYaxisMarks );
showXaxis = in->getAttributeAsBool( "ShowXAxis", showXaxis );
showYaxis = in->getAttributeAsBool( "ShowYAxis", showYaxis );
UseXTickLabels = in->getAttributeAsBool( "ShowXAxisLabels", UseXTickLabels );
UseYTickLabels = in->getAttributeAsBool( "ShowYAxisLabels", UseYTickLabels );
clipPoints = in->getAttributeAsBool( "ClipDrawingRegion", clipPoints );
usePolyPts = in->getAttributeAsBool( "UsePolygons", usePolyPts );
polyRadius = in->getAttributeAsFloat( "PolygonRadius", polyRadius );
polyPts = in->getAttributeAsInt( "PolygonVertices", polyPts );
ReallocateGraphSpace();
}
void irr::gui::SGraph2D::drawOnGraph(
irr::core::vector2df point, irr::video::SColor color
)
{
// Cannot save if the window does not exist
if ( window.getArea() == 0 )
return;
// Shift the origin to the corner
point.X -= window.UpperLeftCorner.X;
point.Y -= window.UpperLeftCorner.Y;
// Convert to the actual GUI window's coordinate system
point.X *= ((irr::f32)AbsoluteRect.getWidth()) / window.getWidth();
point.Y *= ((irr::f32)AbsoluteRect.getHeight()) / window.getHeight();
if ( color.getAlpha() == 0 )
color = point_color;
// Save
graphImage.push_back(
irr::video::S3DVertex( point.X, point.Y, 0,0,0,0, color, 0,0)
);
}
void irr::gui::SGraph2D::drawOnGraph(
irr::f32 x,
irr::f32 y,
irr::video::SColor color
)
{
drawOnGraph( irr::core::vector2df(x,y), color );
}
void irr::gui::SGraph2D::drawOnGraphPolar(
irr::core::vector2df point,
irr::video::SColor color
)
{
// cartesian coordinates
irr::core::vector2df cartesian;
cartesian.X = point.X // radius
* cos( point.Y * irr::core::DEGTORAD ); // cos(angle)
cartesian.Y = point.X // radius
* sin( point.Y * irr::core::DEGTORAD ); // sin(angle)
if ( color.getAlpha() == 0 )
color = point_color;
drawOnGraph( cartesian, color );
}
void irr::gui::SGraph2D::drawOnGraphPolar(
irr::f32 radius,
irr::f32 angle,
irr::video::SColor color
)
{
drawOnGraphPolar( irr::core::vector2df( radius, angle ), color );
}
void irr::gui::SGraph2D::drawRawPoint(
irr::core::vector2df point,
irr::video::SColor color
)
{
// Shift the origin to the corner
point.X -= window.UpperLeftCorner.X
// conversion of shift to GUI element size
* ((irr::f32)AbsoluteRect.getWidth()) / window.getWidth();
point.Y -= window.UpperLeftCorner.Y
// conversion of shift to GUI element size
* ((irr::f32)AbsoluteRect.getHeight()) / window.getHeight();
if ( color.getAlpha() == 0 )
color = point_color;
// Save
graphImage.push_back(
irr::video::S3DVertex( point.X, point.Y, 0,0,0,0, color, 0,0)
);
}
void irr::gui::SGraph2D::drawToGUI(
irr::core::vector2di point,
irr::video::SColor color
)
{
// Do nothing if the window isn't even visible
if ( window.getArea() == 0.0f )
return;
// Flip for drawing on the GUI
point.Y = AbsoluteRect.getHeight() - point.Y;
/* This function has been passed a value that is already prepared to
be drawn to screen and simply needs to be offset. */
point.X += AbsoluteRect.UpperLeftCorner.X;
point.Y += AbsoluteRect.UpperLeftCorner.Y;
// Don't draw points outside the window
if ( clipPoints && !AbsoluteClippingRect.isPointInside( point ) )
return;
// Draw the point as a pixel - might be very small and hard to see
/* - Drawn faster than a polygon and may create a smooth line */
viddriver->drawPixel( point.X, point.Y, color );
// Attempt to draw the point as a polygon (to make it more visible)
if ( usePolyPts && polyRadius >= 1.0f )
viddriver->draw2DPolygon(
point, // position
polyRadius, // radius
color, // color
polyPts // roundness of the point
);
}
void irr::gui::SGraph2D::drawToGUI(
irr::core::line2df line,
irr::video::SColor color
)
{
// Do nothing if the window isn't even visible
// - saves time and prevents divide-by-zero errors
if ( window.getArea() == 0.0f )
return;
if ( AbsoluteClippingRect.getWidth() == 0 || AbsoluteClippingRect.getHeight() == 0 )
return;
/* This function has been passed a value that needs to be prepared
to fit in the window in addition to it being offset. */
// Line that will be drawn - initialized to begin within the GUI element
irr::core::line2di drawline(
AbsoluteRect.UpperLeftCorner.X,
AbsoluteRect.UpperLeftCorner.Y,
AbsoluteRect.UpperLeftCorner.X,
AbsoluteRect.UpperLeftCorner.Y
);
// Tranform the line from graph coordinates.
line.start.X -= window.UpperLeftCorner.X;
line.end.X -= window.UpperLeftCorner.X;
// Flip the y-axis for drawing in irrlicht coordinates
line.start.Y = window.LowerRightCorner.Y - line.start.Y;
line.end.Y = window.LowerRightCorner.Y - line.end.Y;
// starting x
drawline.start.X += (irr::s32) ( line.start.X
* AbsoluteRect.getWidth() / window.getWidth() // coordinate system conversion
);
// starting y
drawline.start.Y += (irr::s32) ( line.start.Y
* AbsoluteRect.getHeight() / window.getHeight() // coordinate system conversion
);
// ending x
drawline.end.X += (irr::s32) ( line.end.X
* AbsoluteRect.getWidth() / window.getWidth() // coordinate system conversion
);
// ending y
drawline.end.Y += (irr::s32) ( line.end.Y
* AbsoluteRect.getHeight() / window.getHeight() // coordinate system conversion
);
// Shorten to fit in the clipping rectangle
if ( drawline.start.X == drawline.end.X ) // Vertical Line
if ( drawline.start.X < AbsoluteClippingRect.UpperLeftCorner.X
|| drawline.start.X > AbsoluteClippingRect.LowerRightCorner.X )
return; // Don't draw
if ( drawline.start.Y == drawline.end.Y ) // Horizontal Line
if ( drawline.start.Y < AbsoluteClippingRect.UpperLeftCorner.Y
|| drawline.start.Y > AbsoluteClippingRect.LowerRightCorner.Y )
return; // Don't draw
// FIXME: We assume only vertical and horizontal lines. Angled lines will be messed up.
drawline.start.X = irr::core::clamp(
drawline.start.X,
AbsoluteClippingRect.UpperLeftCorner.X,
AbsoluteClippingRect.LowerRightCorner.X
);
drawline.start.Y = irr::core::clamp(
drawline.start.Y,
AbsoluteClippingRect.UpperLeftCorner.Y,
AbsoluteClippingRect.LowerRightCorner.Y
);
drawline.end.X = irr::core::clamp(
drawline.end.X,
AbsoluteClippingRect.UpperLeftCorner.X,
AbsoluteClippingRect.LowerRightCorner.X
);
drawline.end.Y = irr::core::clamp(
drawline.end.Y,
AbsoluteClippingRect.UpperLeftCorner.Y,
AbsoluteClippingRect.LowerRightCorner.Y
);
// Draw the line
viddriver->draw2DLine( drawline.start, drawline.end, color );
}
void irr::gui::SGraph2D::drawToGUI(
irr::core::stringw text,
irr::core::position2df pos,
irr::video::SColor color,
bool horiz_centering,
bool vert_centering
)
{
irr::core::recti fin_pos(AbsoluteRect);
fin_pos.LowerRightCorner = fin_pos.UpperLeftCorner;
// Shift center
pos.X -= window.UpperLeftCorner.X;
pos.Y = window.UpperLeftCorner.Y - pos.Y + window.getHeight(); // Flip the y-axis
// coordinate system conversion
pos.X *= (irr::f32)AbsoluteRect.getWidth() / window.getWidth();
pos.Y *= (irr::f32)AbsoluteRect.getHeight() / window.getHeight();
// Move onto the graph (in irrlicht)
fin_pos += irr::core::position2di( (irr::s32)pos.X, (irr::s32)pos.Y );
// Write the text
Environment->getSkin()->getFont()->draw(
text,
fin_pos,
color,
horiz_centering,
vert_centering,
&AbsoluteClippingRect
);
}
#endif // define __SIMPLEGRAPH2D_CPP__

View File

@ -0,0 +1,380 @@
/*
Simple Graph
(c) Nicolaus Anderson
Created Jan 7, 2013
License: Same terms as irrlicht
*/
#include "IGraph2D.h"
#include <Range.h>
#include <IncrementorT.h>
#ifndef __SIMPLEGRAPH2D_H__
#define __SIMPLEGRAPH2D_H__
namespace irr
{
namespace gui
{
//! Class Graph 2D
/*
Purpose: To plot 2D math functions.
*/
class SGraph2D : public IGraph2D
{
//! Graph Image
/* The actual graph itself: a chain of points that need to be
drawn. */
irr::core::array<irr::video::S3DVertex> graphImage;
//! Graph window
/* This is the range of values that the graphed values are forced
to fit into. It is a user-set range. */
irr::core::rectf window;
//! Markers (e.g. tick marks)
bool UseMarkers; // whether to use markers or not
bool UseTicks; // whether to use ticks or lines (if markers are in use)
bool UseXTickLabels; // whether to write labels for the x-axis tick marks
bool UseYTickLabels; // whether to write labels for the y-axis tick marks
irr::f32 markXgap; // spacing between markings on the x-axis
irr::f32 markYgap; // spacing between markings on the y-axis
bool showXaxisMarks; // whether the x-axis marks should be displayed
bool showYaxisMarks; // whether the y-axis marks should be displayed
//! Axis displaying flags
bool showXaxis;
bool showYaxis;
//! Clip points - i.e. Don't draw points outside the graph window
bool clipPoints;
// Polygon point attributes
bool usePolyPts; // Use polygon points
irr::f32 polyRadius; // Radius of the polygon points
irr::s32 polyPts; // Number of points in the polygon
//! Colors
// Background color
irr::video::SColor background_color;
bool hasBackground;
// Axis colors
irr::video::SColor xaxis_color;
irr::video::SColor yaxis_color;
// Point color
irr::video::SColor point_color;
// Tick marks / lines perpendicular to the axis
irr::video::SColor xmark_color;
irr::video::SColor ymark_color;
// The video driver for drawing on screen
irr::video::IVideoDriver* viddriver;
public:
//! Constructor
SGraph2D(
// GUI element parameters
IGUIEnvironment* envir,
IGUIElement* parent,
irr::s32 id,
const irr::core::recti& rectangle,
// Graph parameters
const irr::core::rectf& graphWindow,
bool marks = false,
bool ticks = false,
bool x_labels = true,
bool y_labels = true
)
: IGraph2D( envir, parent, id, rectangle ),
window( graphWindow ),
UseMarkers( marks ),
showXaxisMarks( marks ),
showYaxisMarks( marks ),
UseTicks( ticks ),
UseXTickLabels( x_labels ),
UseYTickLabels( y_labels ),
markXgap(1.0f),
markYgap(1.0f),
showXaxis( true ),
showYaxis( true ),
clipPoints( true ),
usePolyPts( false ),
background_color( irr::video::SColor( 255, 0, 0, 0 ) ),
hasBackground( true ),
xaxis_color( irr::video::SColor( 255, 0, 125, 0 ) ),
yaxis_color( irr::video::SColor( 255, 0, 125, 0 ) ),
point_color( irr::video::SColor( 255, 255, 0, 0 ) ),
xmark_color( irr::video::SColor( 255, 0, 125, 0 ) ),
ymark_color( irr::video::SColor( 255, 0, 125, 0 ) )
{
viddriver = Environment->getVideoDriver();
}
//! Destructor
~SGraph2D()
{
}
//! Set graph size
/* NOT the same as scaling.
This function changes the ranges of values in the graph without changing
the size of the graph as a GUI element.
*/
virtual void setGraphSize( irr::core::rectf& size );
//! Set graph size along one dimension
/* NOT the same as scaling.
This function changes the ranges of values of ONE AXIS in the graph without
changing the size of the graph as a GUI element.
\param size - New axis min or max
\param isMax - If the value given is for the maximum
*/
virtual void setGraphSizeX( irr::f32 size, bool isMax );
virtual void setGraphSizeY( irr::f32 size, bool isMax );
//! Set scale
/* Changes the scale of the ranges of values in the graph without changing
the size of the graph itself.
NOTE: Since this is a scaling, the rectangle being passed in should be the
percentage change (i.e. multiplier for the current values). */
virtual void setGraphScale( irr::core::rectf& scale );
//! Reallocate Memory for Graph
/* In order to allow the graph to draw points quickly, this function is
available to reallocate storage space for the data points.
Old data points will not be destroyed and thus must be overwritten. */
void ReallocateGraphSpace();
protected:
//! Change graph window
/* Corrects the graph points to be drawn correctly in the new graph
window. */
void changeGraphWindow( irr::core::rectf new_win );
public:
//! Get graph size
/* Returns the size of the graph. */
virtual irr::core::rectf getGraphSize();
// Graphing region
//! Get Graph X-Axis Range
/* Returns the range of values that will be visible when the graph is
drawn. */
Range<irr::f32> getXAxisRange();
//! Get Graph Y-Axis Range
/* Returns the range of values that will be visible when the graph is
drawn. */
Range<irr::f32> getYAxisRange();
//! Get Iterable Range for X-Axis
/* Returns an incrementor whose range spans the visible x-axis of the
graph, whose step yields one point per pixel across the screen, and whose
starting position is the one necessary for all points drawn with this as
a guide to cross the entire graph window. */
Inc<irr::f32> getIterableXRange();
//! Get Iterable Range for Y-Axis
/* Returns an incrementor whose range spans the visible y-axis of the
graph, whose step yields one point per pixel across the screen, and whose
starting position is the one necessary for all points drawn with this as
a guide to cross the entire graph window. */
Inc<irr::f32> getIterableYRange();
// Other ----
//! Set step size
/* Sets the spacing between tick marks (if any). */
void markerSpacingX( irr::f32 gap=1.0f );
void markerSpacingY( irr::f32 gap=1.0f );
//! Draw
/* Draws the GUI element. */
virtual void draw();
//! Clear graph
/* Erases everything in the graph. */
virtual void clearGraph();
//! Auto-adjust
/* Corrects the graph window so that all of the points will fit. */
void autoAdjust();
//! Clip points
/* Sets whether points outside the graphing area should be drawn. */
void setPointClipping( bool yes=true);
//-------------------------------
// Drawing area functions / Spaz
//! Set if there is a background
void useBackground( bool use=true );
//! Set background color
/* Sets the color to be displayed behind the graph. */
void setBackgroundColor( irr::video::SColor color );
//! Set point color
/* Sets the color of the points to be displayed. */
virtual void setPointColor( irr::video::SColor color );
//! Set x-axis color
/* Sets the color that will be used in drawing the line representing
the x-axis. */
virtual void setXAxisColor( irr::video::SColor color );
//! Set y-axis color
/* Sets the color that will be used in drawing the line representing
the y-axis. */
virtual void setYAxisColor( irr::video::SColor color );
//! Show x-axis
/* Shows the x-xais if desired. */
void setShowXAxis( bool show=true );
//! Show y-axis
/* Shows the y-axis if desired. */
void setShowYAxis( bool show=true );
//! Draw with polygons
/* Draw the points with polygons. */
void usePolygons( irr::f32 radius=1.5f, irr::s32 corners=4 );
//! Stop drawing with polygons
/* Stops drawing using polygons to draw the points.
Note that you will need to reset the radius if you do this. */
void useNoPolygons();
//! Show X-axis labels
/* Writes the values of the tick marks on the x-axis next to them.
Note: The marks for that axis must actually be visible for the numbers
to appear. */
void showXAxisLabels( bool yes=true );
//! Show Y-axis labels
/* Writes the values of the tick marks on the x-axis next to them.
Note: The marks for that axis must actually be visible for the numbers
to appear. */
void showYAxisLabels( bool yes=true );
//----- Tick marks vs lines
/* Either tick marks (three pixels crossing the line) or perpendicular
lines can be used to show the step size. */
//! Set to use tick marks instead of lines
void useTicks();
//! Set to use perpendicular lines instead of tick marks
void useLines();
//! Set to use no markers
void useNoMarkers();
//! Set to show the x-axis markers
void showXAxisMarkers( bool show=true );
//! Set to show the y-axis markers
void showYAxisMarkers( bool show=true );
//! Set x-axis tick color / perpendicular line color
void setXAxisMarkerColor( irr::video::SColor color );
//! Set y-axis tick color / perpendicular line color
void setYAxisMarkerColor( irr::video::SColor color );
//-----------------------------
//! Serialize attributes
virtual void serializeAttributes(
irr::io::IAttributes* out,
irr::io::SAttributeReadWriteOptions* options=0
);
//! Deserialize attributes
virtual void deserializeAttributes(
irr::io::IAttributes* in,
irr::io::SAttributeReadWriteOptions* options=0
);
//-----------------------------
virtual const c8* getTypeName() const { return staticTypeName(); }
static const c8* staticTypeName() { return "sGraph2D"; }
// ------------ Drawing functions ------------
//! Draw to the graph
/* Draws on the graph a single point whose coordinates are prepared
according to the graph's coordinate system.
You should use this function for standard operations. */
void drawOnGraph(
irr::core::vector2df point,
irr::video::SColor color=irr::video::SColor(0)
);
void drawOnGraph(
irr::f32 x,
irr::f32 y,
irr::video::SColor color=irr::video::SColor(0)
);
//! Draw on the graph - Polar coord
/* Draws on the graph a single point whose coordinates are prepared
according to the graph's coordinate system but are polar corrdinates.
\param point - A radius (X value) and an angle (Y value).
You should use this function for standard operations. */
void drawOnGraphPolar(
irr::core::vector2df point,
irr::video::SColor color=irr::video::SColor(0)
);
void drawOnGraphPolar(
irr::f32 radius,
irr::f32 angle,
irr::video::SColor color=irr::video::SColor(0)
);
//! Draw to the graph
/* Draws on the graph a single point whose coordinates are preppared for
the AbsoluteRect and need merely be shifted. */
void drawRawPoint(
irr::core::vector2df point,
irr::video::SColor color=irr::video::SColor(0)
);
protected:
//! Draw directly to the GUI element
/* Draws to the GUI element by handling the relative offset
of the GUI element from the upperleft corner of the screen. */
void drawToGUI( irr::core::vector2di point, irr::video::SColor color );
void drawToGUI( irr::core::line2df line, irr::video::SColor color );
void drawToGUI(
irr::core::stringw text,
irr::core::position2df pos,
irr::video::SColor color,
bool horiz_centering,
bool vert_centering
);
};
} // end namespace gui
} // end namespace irr
#endif // define __SIMPLEGRAPH2D_H__

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

View File

@ -0,0 +1,182 @@
/*
By Nic Anderson
Used for debugging SGraph2D, the simple implementation of Graph2D.
*/
#include <iostream>
using std::cout;
#include <irrlicht.h>
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif
#include "SGraph2D.h"
using namespace irr;
using namespace gui;
void plotsine( SGraph2D* );
void plotline( SGraph2D* );
void plotspin( SGraph2D* );
void plotspintrail( SGraph2D* );
void plotsine( SGraph2D* win )
{
Inc<f32> dis;
core::vector2df pt;
dis.copy( win->getIterableXRange() );
dis.setStep( 1.0f / 1000.0f );
do {
pt.X = dis.Val();
pt.Y = 10 * sin( dis.Val() );
win->drawOnGraph( pt, video::SColor(255,255,0,0) );
} while ( !++dis );
}
void plotline( SGraph2D* win )
{
Inc<f32> dis;
core::vector2df pt;
dis.copy( win->getIterableXRange() );
dis.setStep( 1.0f / 1000.0f );
do {
pt.X = dis.Val();
pt.Y = dis.Val();
win->drawOnGraph( pt, video::SColor(255,255,0,0) );
} while ( !++dis );
}
void plotspin( SGraph2D* win )
{
Inc<f32> twirl( CYC_DEFAULT, 0.0f, 0.1f, 0.0f, 360.0f );
do {
win->drawOnGraphPolar(
5*cos( 5*twirl.Val() ), // alternating radius
twirl.Val() / core::DEGTORAD,
video::SColor(
255,
0,//(((s32)twirl.Val()*5)%255),
(((s32)twirl.Val()*5+100)%255),
(((s32)twirl.Val()*5+200)%255)
)
);
} while ( !++twirl );
}
void plotspintrail( SGraph2D* win )
{
static s32 loops=6; // # loops per flower
static f32 sizeup;
static f32 spacing = 1.2f;
static f32 shiftup = 2;
static f32 resolution = 200;
Inc<f32> twirl( CYC_DEFAULT, 0.0f, 1.0f, 0.0f, (f32)loops );
Inc<f32> innertwirl( CYC_DEFAULT, 0.0f, 1.0f, 0.0f, 360.0f );
core::vector2df pt;
do {
innertwirl.setStep( 360.0f / (twirl.Val() + 1) / resolution );
do {
sizeup = twirl.Val() + shiftup;
// Create point in polar coordinates
// radius
pt.X = sizeup // increasing size
// alternating radius
* cos( loops * innertwirl.Val() * core::DEGTORAD );
// Convert to cartessian
pt.Y = pt.X * sin( innertwirl.Val() * core::DEGTORAD );
pt.X = pt.X * cos( innertwirl.Val() * core::DEGTORAD );
// Offset
pt.X += //(loops - sizeup + shiftup)
spacing * sizeup * cos( twirl.Val() * 360 / loops * core::DEGTORAD );
pt.Y += //(loops - sizeup + shiftup)
spacing * sizeup * sin( twirl.Val() * 360 / loops * core::DEGTORAD );
// Draw
win->drawOnGraph(
pt,
video::SColor(
255,
0,//(((s32)twirl.Val()*360*5)%255),
(((s32)twirl.Val()*360*5+100)%255),
(((s32)twirl.Val()*360*5+200)%255)
)
);
} while ( !++innertwirl );
innertwirl.restart();
} while ( !++twirl );
}
void main()
{
IrrlichtDevice* device = createDevice(
video::EDT_BURNINGSVIDEO,
irr::core::dimension2du( 1000,700 )
);
video::IVideoDriver* vid = device->getVideoDriver();
IGUIEnvironment* envir = device->getGUIEnvironment();
SGraph2D* graph = new SGraph2D(
envir, // environment
envir->getRootGUIElement(), // parent
0, // id
irr::core::recti(50,50,800,600), // element boundaries
irr::core::rectf(-10.0f,-15.0f,15.0f,10.0f), // graph window
true, // marks?
true // ticks?
);
graph->setBackgroundColor( video::SColor(255,200,200,200) );
graph->usePolygons( 2, 4 );
graph->setPointClipping( false );
graph->markerSpacingX( 1.5 );
//plotsine( graph );
//plotline( graph );
//plotspin( graph );
plotspintrail( graph );
graph->autoAdjust();
graph->setGraphScale( irr::core::rectf( 1.1f, 1.1f, 1.1f, 1.2f ) );
graph->drop();
graph = 0;
// Change the font
//envir->getSkin()->getFont()->setKerningHeight(14);
//envir->getSkin()->getFont()->setKerningWidth(14);
while ( device->run() )
{
vid->beginScene();
envir->drawAll();
vid->endScene();
}
device->drop();
}

View File

@ -0,0 +1,36 @@
/*
(c) Nicolaus Anderson
*/
#pragma once
/*
Enum for changing the size settings of the central window menu.
*/
enum ECWMSize
{
/* Default settings (450px wide, 400px tall). */
ECWMSize_default =0,
/* Attempts to size the window to neatly fit the available
program window size.
Applies to both the width and height. */
ECWMSize_optimize,
/* Makes the size constant.
Applies to both the width and height. */
ECWMSize_constant,
// specifically the width
ECWMSize_width_default,
ECWMSize_width_optimize,
ECWMSize_width_constant,
// specifically the height
ECWMSize_height_default,
ECWMSize_height_optimize,
ECWMSize_height_constant,
// count
ECWMSize_COUNT
};

View File

@ -0,0 +1,73 @@
/*
(c) Nicolaus Anderson
*/
#pragma once
/*
Enumeration for giving the location of a menu
(for the Ultra GUI Menu).
*/
enum EUltraMenuLocation
{
// Left side menu
EUGUIMLoc_Left=0,
// Central window menu
EUGUIMLoc_Center,
// Right side menu
EUGUIMLoc_Right,
// Menu bar
EUGUIMLoc_Bar,
// Total available locations
EUGUIMLoc_COUNT
};
enum EUltraMenuState
{
// hidden completely
EUGUIMState_Closed=0,
// closing
EUGUIMState_Closing,
// open
EUGUIMState_Open,
// opening
EUGUIMState_Opening,
// becoming left-side menu
EUGUIMState_ToLeft_Open,
EUGUIMState_ToLeft_Closed,
// becoming right-side menu
EUGUIMState_ToRight_Open,
EUGUIMState_ToRight_Closed,
// becoming central window menu
EUGUIMState_ToCenter_Open,
EUGUIMState_ToCenter_Closed,
// becoming bar menu icon
EUGUIMState_ToBar,
// Total number of states
EUGUIMState_COUNT
};
// What to do when told to close
enum EUltraMenuClose
{
// Default - hide to the side
EUGUIMClose_Hide=0,
// Minimize
EUGUIMClose_Minimize,
// Number of options
EUGUIMClose_COUNT
};

View File

@ -0,0 +1,92 @@
/*
(c) Nicolaus Anderson
*/
#include "Searchable.h"
Searchable::Searchable()
{
}
Searchable::~Searchable()
{
tags.clear();
}
void Searchable::addTag(const wchar_t* tag)
{
tags.push_back(tag);
}
void Searchable::addTag( const irr::core::stringw& tag )
{
tags.push_back(tag);
}
void Searchable::addTags( const irr::core::stringw& list )
{
// parse the string
irr::core::stringw next;
irr::u32 s=0;
for ( ; s < list.size(); s++ )
{
if ( list[s] == ',' )
{
if ( next.size() > 0 )
tags.push_back(next);
next.clear();
}
else {
if ( list[s] != ' ' && list[s] != '\n' && list[s] != '\r' && list[s] != '\t' )
{
next.push_back(list[s]);
}
}
}
}
irr::core::stringw Searchable::getTags()
{
irr::core::stringw out;
irr::u32 t=0;
for ( ; t < tags.size(); t++ )
{
out.append( tags[t] );
if ( t != tags.size() - 1 )
out.append( irr::core::stringw(", ") );
}
return out;
}
bool Searchable::hasMatchingTagExactly( irr::core::stringw& tag )
{
irr::u32 t=0;
for ( ; t < tags.size(); t++ )
{
if ( tags[t].size() == tag.size() && tags[t].equalsn(tag, tag.size()) )
return true;
}
return false;
}
bool Searchable::hasMatchingTagPartial( irr::core::stringw& tag )
{
irr::u32 t=0;
for ( ; t < tags.size(); t++ )
{
if ( tags[t].equalsn(tag, tag.size()) )
return true;
}
return false;
}
void Searchable::shouldShow( bool setting )
{
}

View File

@ -0,0 +1,42 @@
/*
(c) Nicolaus Anderson
*/
#include <irrlicht.h>
#pragma once
//! Class Searchable
/*
An object that can be searched.
*/
class Searchable
{
protected:
irr::core::array<irr::core::stringw> tags;
public:
Searchable();
~Searchable();
virtual void addTag( const wchar_t* tag );
virtual void addTag( const irr::core::stringw tag );
/* Add comma-separated tags. */
virtual void addTags( const irr::core::stringw list );
/* Get tags */
virtual irr::core::stringw getTags();
/* Has a tag that matches exactly the given one. */
virtual bool hasMatchingTagExactly( irr::core::stringw& tag );
/* Has a partially matching tag. */
virtual bool hasMatchingTagPartial( irr::core::stringw& tag );
/* Called by search engines to indicate whether this object
should show up in the search results. For listed GUI elements,
this may mean being excluded from the drawing order. */
virtual void shouldShow( bool setting );
};

View File

@ -0,0 +1,74 @@
/*
(c) Nicolaus Anderson
*/
/* A list of constants used for UltraGUI.
Feel free to modify these constants to suit your purposes. */
/* Resouce path function.
This is the default resource path option. It can be changed here
to change the default, or you can pass to the constructor a resource
path. */
#ifndef ULTRAGUI_RESOURCE_PATH
#define ULTRAGUI_RESOURCE_PATH irr::io::path("../resources/art/")
#endif
/* Button imagery. Appended to the resource path in order to obtain
the imagery for display on the buttons. */
#define ULTRAGUI_RESOURCE_CLOSEBUTTON "closeButton.png"
#define ULTRAGUI_RESOURCE_TOLEFTBUTTON "toLeftButton.png"
#define ULTRAGUI_RESOURCE_TORIGHTBUTTON "toRightButton.png"
#define ULTRAGUI_RESOURCE_TOCENTERBUTTON "toCenterButton.png"
#define ULTRAGUI_RESOURCE_MINIMIZEBUTTON "minimizeButton.png"
#define ULTRAGUI_RESOURCE_NOHOVERTEXTURE ""
#define ULTRAGUI_RESOURCE_HOVERTEXTURE_0 "hoverTex0.png"
#define ULTRAGUI_RESOURCE_HOVERTEXTURE_1 "hoverTex1.png"
#define ULTRAGUI_RESOURCE_HOVERTEXTURE_2 "hoverTex2.png"
#define ULTRAGUI_RESOURCE_HOVERTEXTURE_3 "hoverTex3.png"
/* Size of an UltraGUIMenu as it appears on the menu bar
of the UltraGUIFrame: */
#define ULTRAGUI_DEFAULT_MENUBAR_BUTTON_WIDTH 80
#define ULTRAGUI_DEFAULT_MENUBAR_BUTTON_HEIGHT 30
/* Spacing between a UltraGUIMenu bar and the edge of the menu bar
of UltraGUIFrame: */
#define ULTRAGUI_MENUBAR_PADDING 4
#define ULTRAGUI_DEFAULT_CENTRAL_MENU_WIDTH 500
#define ULTRAGUI_DEFAULT_CENTRAL_MENU_HEIGHT 400
#define ULTRAGUI_DEFAULT_SIDE_MENU_WIDTH 250
#define ULTRAGUI_DEFAULT_SIDE_MENU_HEIGHT 500
#define ULTRAGUI_DEFAULT_MOVE_SPEED 0.005f
/* Default header information: */
#define ULTRAGUI_DEFAULT_MENU_HEADER_HEIGHT 30
// Plain header colors (easier to read text on)
//#define ULTRAGUI_DEFAULT_HEADER_COLOR_TOP irr::video::SColor(255,0,100,155)
//#define ULTRAGUI_DEFAULT_HEADER_COLOR_MID irr::video::SColor(255,0,50,95)
//#define ULTRAGUI_DEFAULT_HEADER_COLOR_BOTTOM irr::video::SColor(255,0,70,135)
// Slick header colors
#define ULTRAGUI_DEFAULT_HEADER_COLOR_TOP irr::video::SColor(255,140,180,205)
#define ULTRAGUI_DEFAULT_HEADER_COLOR_MID irr::video::SColor(255,0,50,95)
#define ULTRAGUI_DEFAULT_HEADER_COLOR_BOTTOM irr::video::SColor(255,20,110,165)
/* Size of the width or height of a button on an UltraGUIMenu.
For now, set to match small texture size (16x16) to load without image
manipulation or engine modification. */
#define ULTRAGUI_DEFAULT_MENU_BUTTON_SIZE 16
// Button hover color
#define ULTRAGUI_DEFAULT_MENU_BUTTON_HOVERCOLOR irr::video::SColor( 255,255,255,255 )
//irr::video::SColor( 155,40,200,255 )
/* The spacing between the first button of an UltraGUIMenu
and the right side of the menu. */
#define ULTRAGUI_BUTTON_RIGHT_PADDING 5
/* The time (in milliseconds) that the menus are highlighted. */
#define ULTRAGUI_HIGHLIGHT_TIME 1000

View File

@ -0,0 +1,672 @@
#include "UltraGUIFrame.h"
namespace irr
{
namespace gui
{
UltraGUIFrame::UltraGUIFrame(
IGUIEnvironment* environment,
ICursorControl* cursorc, /* Not implemented yet: Change cursor to arrow when menu is movable */
irr::s32 id,
IGUIElement* parent,
recti rectangle
)
: IGUIElement(
EGUIET_ELEMENT,
environment,
(parent? parent : environment->getRootGUIElement()),
id,
(rectangle!=recti()? rectangle : (parent? parent->getAbsolutePosition() : environment->getRootGUIElement()->getAbsolutePosition()))
)
, cursor( cursorc )
, menuBarRows( 1 )
, lastOpenBarX( 0 )
, lastOpenRow( 0 )
, leftSideSize(
dimension2du(
ULTRAGUI_DEFAULT_SIDE_MENU_WIDTH,
ULTRAGUI_DEFAULT_SIDE_MENU_HEIGHT
)
)
, rightSideSize(
dimension2du(
ULTRAGUI_DEFAULT_SIDE_MENU_WIDTH,
ULTRAGUI_DEFAULT_SIDE_MENU_HEIGHT
)
)
, centerSize(
dimension2du(
ULTRAGUI_DEFAULT_CENTRAL_MENU_WIDTH,
ULTRAGUI_DEFAULT_CENTRAL_MENU_HEIGHT
)
)
, barSlotSize(
dimension2du(
ULTRAGUI_DEFAULT_MENUBAR_BUTTON_WIDTH,
ULTRAGUI_DEFAULT_MENUBAR_BUTTON_HEIGHT
)
)
, headerHeight( ULTRAGUI_DEFAULT_MENU_HEADER_HEIGHT )
, spriteBank( 0 )
{
/* Save the size for use in scaling the menus if this frame
is ever resized. */
oldRect = (rectangle!=recti()? rectangle : (parent? parent->getAbsolutePosition() : environment->getRootGUIElement()->getAbsolutePosition()));
/* Set the size of the bar on which everything is drawn. */
menuBarRect = recti(
oldRect.UpperLeftCorner.X,
oldRect.LowerRightCorner.Y - ULTRAGUI_DEFAULT_MENUBAR_BUTTON_HEIGHT,
oldRect.LowerRightCorner.X,
oldRect.LowerRightCorner.Y
);
}
UltraGUIFrame::~UltraGUIFrame()
{
if ( spriteBank )
spriteBank->drop();
// The IGUIElement destructor will release the children
}
UltraGUIMenu* UltraGUIFrame::addMenu( irr::s32 menuID, irr::video::ITexture* icon )
{
// Rectangle of the menu (left-side shape)
//recti shape(
// AbsoluteRect.UpperLeftCorner.X - (irr::s32)leftSideSize.Width, // Set off screen
// menuBarRect.UpperLeftCorner.Y - (irr::s32)leftSideSize.Height, // Set above the menu bar
// AbsoluteRect.UpperLeftCorner.X, // Set off screen
// menuBarRect.UpperLeftCorner.Y // Set above the menu bar
// );
recti shape(
AbsoluteRect.UpperLeftCorner.X,
menuBarRect.UpperLeftCorner.Y - (irr::s32)leftSideSize.Height,
AbsoluteRect.UpperLeftCorner.X + (irr::s32)leftSideSize.Width,
menuBarRect.UpperLeftCorner.Y
);
// Create the menu
// This step also makes the menu a child of this element
UltraGUIMenu* menu = new UltraGUIMenu( this, menuID, shape );
menu->setLeftSize( dimension2du(shape.getSize()) );
menu->setRightSize( dimension2du(shape.getSize()) );
menu->setCenterSize(
dimension2du(
ULTRAGUI_DEFAULT_CENTRAL_MENU_WIDTH,
ULTRAGUI_DEFAULT_CENTRAL_MENU_HEIGHT
)
);
menu->setBarSize(
dimension2du(
ULTRAGUI_DEFAULT_MENUBAR_BUTTON_WIDTH,
ULTRAGUI_DEFAULT_MENUBAR_BUTTON_HEIGHT
)
);
if ( icon )
menu->setMenuBarSprite( icon );
// Now have the menu locate it in the correct place
menu->setMyState( EUGUIMState_ToLeft_Open, true );
menu->snapState();
// Make sure the buttons appear
menu->refreshButtons();
// unnecessary when there is an updateAbsolutePosition() call
return menu;
}
void UltraGUIFrame::removeMenu( irr::s32 menuID )
{
// Search the children for the menu
irr::core::list<IGUIElement*>::Iterator kid;
for ( ; kid != Children.end(); ++kid )
{
if ( (*kid)->getID() == menuID )
{
/* Menu bar menus need to be removed to deallocate space on the bar,
allowing other menus to occupy the slot once occupied by this menu. */
if ( ((UltraGUIMenu*)(*kid))->getMenuLocation() == EUGUIMLoc_Bar )
{
leavingBar( (UltraGUIMenu*)(*kid) );
}
removeChild(*kid);
}
}
}
void UltraGUIFrame::closeMenu( irr::s32 menuID )
{
UltraGUIMenu* result=0;
if ( getMenu( menuID, result ) )
result->setMyState( EUGUIMState_Closed );
}
void UltraGUIFrame::closeOpenMenuAtLocation( EUltraMenuLocation location )
{
irr::core::list<IGUIElement*>::Iterator kid = Children.begin();
for ( ; kid != Children.end(); ++kid )
{
if ( ((UltraGUIMenu*)(*kid))->getMenuLocation() == location )
{
((UltraGUIMenu*)(*kid))->setMyState( EUGUIMState_Closed );
}
}
}
void UltraGUIFrame::openMenu( irr::s32 menuID )
{
UltraGUIMenu* result=0;
irr::core::list<IGUIElement*>::Iterator kid = Children.begin();
if ( !getMenu( menuID, result ) )
return;
for ( ; kid != Children.end(); ++kid )
{
if ( ((UltraGUIMenu*)(*kid))->getMenuLocation() == result->getMenuLocation() )
{
if ( (*kid) == result )
{
((UltraGUIMenu*)(*kid))->setMyState( EUGUIMState_Open);
} else {
((UltraGUIMenu*)(*kid))->setMyState( EUGUIMState_Closed );
}
}
}
}
void UltraGUIFrame::moveMenu( irr::s32 menuID, EUltraMenuLocation location )
{
UltraGUIMenu* result=0;
if ( !getMenu( menuID, result ) )
return;
switch ( result->getMenuState() )
{
case EUGUIMState_Open:
switch ( location )
{
case EUGUIMLoc_Right:
result->setMyState( EUGUIMState_ToRight_Open );
break;
case EUGUIMLoc_Center:
result->setMyState( EUGUIMState_ToCenter_Open);
break;
case EUGUIMLoc_Bar:
result->setMyState( EUGUIMState_ToBar );
break;
default: // Move to left
result->setMyState( EUGUIMState_ToLeft_Open );
break;
}
break;
default:
// Assume closed state
switch ( location )
{
case EUGUIMLoc_Right:
result->setMyState( EUGUIMState_ToRight_Closed );
break;
case EUGUIMLoc_Center:
result->setMyState( EUGUIMState_ToCenter_Closed );
break;
case EUGUIMLoc_Bar:
result->setMyState( EUGUIMState_ToBar );
break;
default: // Move to left
result->setMyState( EUGUIMState_ToLeft_Closed );
break;
}
break;
}
//updateAbsolutePosition();
}
void UltraGUIFrame::setMenuState( irr::s32 menuID, EUltraMenuState state )
{
/* Note that the opening of any menu requires the closing of
another unless that menu is a bar menu (in which case it can't close). */
// Find the menu
UltraGUIMenu* menu =0;
// Menu not found, so terminate processing
if ( !getMenu( menuID, menu ) )
return;
/* Both the state and location of the menu determine the next
course of action. */
switch ( state )
{
case EUGUIMState_Opening:
case EUGUIMState_Open:
closeOpenMenuAtLocation( menu->menuLocation );
menu->setMyState( EUGUIMState_Open );
bringToFront( menu );
break;
case EUGUIMState_Closing:
case EUGUIMState_Closed:
menu->setMyState( EUGUIMState_Closed );
break;
default:
menu->setMyState( state );
if ( state == EUGUIMState_ToLeft_Open
|| state == EUGUIMState_ToRight_Open
|| state == EUGUIMState_ToCenter_Open
)
{
bringToFront(menu);
}
break;
}
}
bool UltraGUIFrame::getMenu( irr::s32 menuID, UltraGUIMenu*& result )
{
irr::core::list<IGUIElement*>::Iterator it = Children.begin();
for ( ; it != Children.end(); ++it )
{
if ( (*it)->getID() == menuID )
{
result = (UltraGUIMenu*)(*it);
return true;
}
}
// Not found
return false;
}
void UltraGUIFrame::requestBarSpace( UltraGUIMenu* menu )
{
/* Calculate if a new row needs to be added for the menu. */
if ( lastOpenBarX + (irr::s32)menu->getBarSize().Width
> menuBarRect.getWidth() ) // + ULTRAGUI_MENUBAR_PADDING )
{
// Add new row
menuBarRows++;
menuBarRect.UpperLeftCorner.Y = AbsoluteRect.LowerRightCorner.Y - (menuBarRows * ULTRAGUI_DEFAULT_MENUBAR_BUTTON_HEIGHT);
// Set the new last opening
lastOpenBarX = 0; // ULTRAGUI_MENUBAR_PADDING;
occupiedBarX = menu->getBarSize().Width; // ULTRAGUI_MENUBAR_PADDING;
lastOpenRow++;
} else {
occupiedBarX = lastOpenBarX + menu->getBarSize().Width;
}
/* Since minimized bars should not have the focus, search
for the first open menu that is not on the bar. */
irr::core::list<IGUIElement*>::Iterator iter = Children.begin();
for ( ; iter != Children.end(); ++iter )
{
if ( *iter != menu
&& ((UltraGUIMenu*)*iter)->isTrulyOpen() )
{
bringToFront( *iter );
break;
}
}
}
void UltraGUIFrame::leavingBar( UltraGUIMenu* menu )
{
// Reset and reprepare
lastOpenBarX = 0; // ULTRAGUI_MENUBAR_PADDING;
occupiedBarX = 0; // ULTRAGUI_MENUBAR_PADDING;
menuBarRows = 1;
menuBarRect.UpperLeftCorner.Y = AbsoluteRect.LowerRightCorner.Y - (menuBarRows * ULTRAGUI_DEFAULT_MENUBAR_BUTTON_HEIGHT);
irr::core::list<IGUIElement*>::Iterator iter = Children.begin();
for ( ; iter != Children.end(); ++iter )
{
if ( *iter != menu
&& ((UltraGUIMenu*)*iter)->getMenuLocation() == EUGUIMLoc_Bar )
{
((UltraGUIMenu*)*iter)->refresh();
}
}
}
IGUISpriteBank* UltraGUIFrame::getMenuSpriteBank()
{
// Has the sprite bank already been created?
if ( spriteBank )
{
return spriteBank;
}
/* Create the sprite bank for the button highlighters.
One to two sprites will be created:
1) An on-mouse-hover sprite, which is blue.
2) An on-click sprite, which is white. */
spriteBank = getEnvironment()->addEmptySpriteBank( ULTRAGUI_RESOURCE_PATH + "ultraMenuSpriteBank" );
/* Create the frames for the hover sprite. Note that all of them have
the same size. */
SGUISpriteFrame noHoverFrame;
noHoverFrame.rectNumber = 0;
noHoverFrame.textureNumber = 0;
SGUISpriteFrame hoverFrame0;
hoverFrame0.rectNumber = 0;
hoverFrame0.textureNumber = 1;
SGUISpriteFrame hoverFrame1;
hoverFrame1.rectNumber = 0;
hoverFrame1.textureNumber = 2;
SGUISpriteFrame hoverFrame2;
hoverFrame2.rectNumber = 0;
hoverFrame2.textureNumber = 3;
SGUISpriteFrame hoverFrame3;
hoverFrame3.rectNumber = 0;
hoverFrame3.textureNumber = 4;
// sprite for when the mouse hovers over the button
SGUISprite hoverSprite;
hoverSprite.frameTime = 100; // 100 ms
hoverSprite.Frames.push_back( noHoverFrame );
hoverSprite.Frames.push_back( hoverFrame0 );
hoverSprite.Frames.push_back( hoverFrame1 );
hoverSprite.Frames.push_back( hoverFrame2 );
hoverSprite.Frames.push_back( hoverFrame3 );
// sprite for when the mouse moves off the button
// just a simple reverse of the first sprite
SGUISprite hoverOffSprite;
hoverOffSprite.frameTime = 100; // 100 ms
hoverOffSprite.Frames.push_back( hoverFrame2 );
hoverOffSprite.Frames.push_back( hoverFrame1 );
hoverOffSprite.Frames.push_back( hoverFrame0 );
hoverOffSprite.Frames.push_back( noHoverFrame );
// add the sprites to the bank
spriteBank->getSprites().push_back( hoverSprite );
spriteBank->getSprites().push_back( hoverOffSprite );
// add the button area rectangle to the bank
spriteBank->getPositions().push_back(
irr::core::recti(
0,0,
ULTRAGUI_DEFAULT_MENU_BUTTON_SIZE,
ULTRAGUI_DEFAULT_MENU_BUTTON_SIZE
)
);
// add the on-hover textures to the bank
spriteBank->addTexture(
getEnvironment()->getVideoDriver()->getTexture(
ULTRAGUI_RESOURCE_PATH + ULTRAGUI_RESOURCE_NOHOVERTEXTURE
) );
spriteBank->addTexture(
getEnvironment()->getVideoDriver()->getTexture(
ULTRAGUI_RESOURCE_PATH + ULTRAGUI_RESOURCE_HOVERTEXTURE_0
) );
spriteBank->addTexture(
getEnvironment()->getVideoDriver()->getTexture(
ULTRAGUI_RESOURCE_PATH + ULTRAGUI_RESOURCE_HOVERTEXTURE_1
) );
spriteBank->addTexture(
getEnvironment()->getVideoDriver()->getTexture(
ULTRAGUI_RESOURCE_PATH + ULTRAGUI_RESOURCE_HOVERTEXTURE_2
) );
spriteBank->addTexture(
getEnvironment()->getVideoDriver()->getTexture(
ULTRAGUI_RESOURCE_PATH + ULTRAGUI_RESOURCE_HOVERTEXTURE_3
) );
return spriteBank;
}
bool UltraGUIFrame::OnEvent( const irr::SEvent& event )
{
// For now, unless features are added
return IGUIElement::OnEvent(event);
}
void UltraGUIFrame::updateAbsolutePosition()
{
// Reset the menu bar count and rows
lastOpenBarX = ULTRAGUI_MENUBAR_PADDING;
lastOpenRow = 0;
// Save the old rectangle
// It will be needed by the menus for repositioning and resizing
oldRect = AbsoluteRect;
// Do NOT do: IGUIElement::updateAbsolutePosition();
// since the children should be updated last.
recalculateAbsolutePosition(false);
/* Recalculating here updates the AbsoluteRect, making its size different
from the previous size (in oldSize) if in fact the size has been changed. */
// Update the child sizes stored here (in ultra frame)
// By this, I mean update the sizes in case the frame itself has changed.
// This is probably unnecessary.
// To do??
// Update the menu bar rectangle
/* This is necessary in the event that another slot on the
menu bar is requested. */
menuBarRect.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X;
menuBarRect.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X;
menuBarRect.LowerRightCorner.Y = AbsoluteRect.LowerRightCorner.Y;
menuBarRect.UpperLeftCorner.Y =
AbsoluteRect.LowerRightCorner.Y
- menuBarRows * ULTRAGUI_DEFAULT_MENUBAR_BUTTON_HEIGHT;
/* Eventually, I may add a spacer between the top of the bar and the
button. However, it would require considering such spacing in the
function getBarSlotPosition(). */
// Now update the child elements
irr::core::list<IGUIElement*>::Iterator it = Children.begin();
for (; it != Children.end(); ++it)
{
(*it)->updateAbsolutePosition();
}
}
void UltraGUIFrame::draw()
{
if ( !isVisible() )
return;
// Draw the menu bar
Environment->getSkin()->draw3DMenuPane(this, menuBarRect);
// Draw Everything else
IGUIElement::draw();
}
void UltraGUIFrame::OnPostRender(irr::u32 timeMs)
{
IGUIElement::OnPostRender(timeMs);
}
bool UltraGUIFrame::isPointInside( const irr::core::vector2di& point ) const
{
/* Normally, the clipping rectangle is used.
Whether it should be used here is unknown, but AbsoluteRect
should work. */
return AbsoluteRect.isPointInside(point);
}
vector2di UltraGUIFrame::getLeftSidePosition()
{
// Place on the left side just above the menu bar
return vector2di(
AbsoluteRect.UpperLeftCorner.X,
AbsoluteRect.LowerRightCorner.Y - menuBarRect.getHeight()
);
}
vector2di UltraGUIFrame::getRightSidePosition()
{
// Place on the right size just above the menu bar
return vector2di(
AbsoluteRect.LowerRightCorner.X,
AbsoluteRect.LowerRightCorner.Y - menuBarRect.getHeight()
);
}
vector2di UltraGUIFrame::getCenterCenterPosition()
{
// Place directly in the center of the screen (for now)
return (AbsoluteRect.UpperLeftCorner + AbsoluteRect.LowerRightCorner)/2;
// same as AR.ULC + (AR.LRC - AR.ULC)/2
}
vector2di UltraGUIFrame::getBarSlotPosition()
{
/* This requires that the first position be reset by
updateAbsolutePosition of this class. */
vector2di slot( lastOpenBarX, menuBarRect.LowerRightCorner.Y - menuBarRect.getHeight() );
/* Indicate the slot has now been occupied by setting
the next open slot to the location after this one. */
lastOpenBarX = occupiedBarX;
return slot;
}
dimension2du UltraGUIFrame::getCenterWindowSize()
{
/* Calculate the size based on the defaults and the
available screen size. */
// Initialize the window size to the set size.
dimension2du windowSize = centerSize;
/* In the future, the window may be resized according to a
user-selected option. */
/* The window is supposed to be 90% of the width and 80% of
the height of the available space AT MAXIMUM.
If it is smaller than that, no change is made to its size. */
irr::u32 widthMax = (irr::u32) ( 0.9f * (irr::f32)AbsoluteRect.getWidth() );
irr::u32 heightMax = (irr::u32) ( 0.8f * (irr::f32)AbsoluteRect.getHeight() );
if ( windowSize.Width > widthMax )
windowSize.Width = widthMax;
if ( windowSize.Height > heightMax )
windowSize.Height = heightMax;
return windowSize;
}
irr::s32 UltraGUIFrame::getBarHeight()
{
return menuBarRect.getHeight();
}
bool UltraGUIFrame::isInLeftDragRegion( irr::s32 x, irr::s32 y )
{
// Left side of the region
if ( x < AbsoluteRect.UpperLeftCorner.X )
return false;
// Bottom of the region
if ( y > AbsoluteRect.LowerRightCorner.Y - menuBarRect.getHeight() )
return false;
// Right side of the region = 15% frame width (as opposed to leftSideSize.Width)
if ( x > AbsoluteRect.UpperLeftCorner.X + (AbsoluteRect.getWidth()*0.15) )
return false;
// Top of the region = 15% frame height (as opposed to leftSideSize.Height)
if ( y < AbsoluteRect.LowerRightCorner.Y - (AbsoluteRect.getHeight()*0.85) - menuBarRect.getHeight() )
return false;
// Must be inside
return true;
}
bool UltraGUIFrame::isInRightDragRegion( irr::s32 x, irr::s32 y )
{
// Right side of the region
if ( x > AbsoluteRect.LowerRightCorner.X )
return false;
// Bottom of the region
if ( y > AbsoluteRect.LowerRightCorner.Y - menuBarRect.getHeight() )
return false;
// Left side of the region = 15% frame width (as opposed to rightSideSize.Width)
if ( x < AbsoluteRect.LowerRightCorner.X - (AbsoluteRect.getWidth()*0.15) )
return false;
// Top of the region = 15% frame height (as opposed to rightSideSize.Height)
if ( y < AbsoluteRect.LowerRightCorner.Y - (AbsoluteRect.getHeight()*0.85) - menuBarRect.getHeight() )
return false;
// Must be inside
return true;
}
bool UltraGUIFrame::isInCenterDragRegion( irr::s32 x, irr::s32 y )
{
// Left side of the region = 35% frame width
if ( x < AbsoluteRect.UpperLeftCorner.X + (AbsoluteRect.getWidth()*0.35) )
return false;
// Right side of the region = (100-35)% frame width
if ( x > AbsoluteRect.LowerRightCorner.X - (AbsoluteRect.getWidth()*0.35) )
return false;
// Top of the region = 10% frame height
if ( y < AbsoluteRect.UpperLeftCorner.X + (AbsoluteRect.getHeight()*0.1) )
return false;
// Bottom of the region = (100-35)% frame height
// Note, this may cause collisions with the menu bar for very tiny screens, haha
if ( y > AbsoluteRect.LowerRightCorner.Y - (AbsoluteRect.getHeight()*0.35) )
return false;
// Must be inside
return true;
}
bool UltraGUIFrame::isInBarDragRegion( irr::s32 x, irr::s32 y )
{
irr::core::vector2di pt(x,y);
if ( menuBarRect.isPointInside( pt ) )
return true;
return false;
}
recti UltraGUIFrame::getFrameRectChange()
{
vector2di ulc( AbsoluteRect.UpperLeftCorner - oldRect.UpperLeftCorner );
vector2di lrc( AbsoluteRect.LowerRightCorner - oldRect.LowerRightCorner );
return recti( ulc, lrc );
}
}} // end namespace gui and irr

View File

@ -0,0 +1,265 @@
/*
(c) Nicolaus Anderson
*/
#include <irrlicht.h>
#include "UltraGUIConstants.h"
//#include "EnumCentralWindowMenuSizing.h"
#include "EnumUltraMenuState.h"
#include "UltraGUIMenu.h"
using irr::core::vector2di;
using irr::core::dimension2du;
using irr::core::recti;
#ifndef _ULTRAGUIFRAME_
#define _ULTRAGUIFRAME_
namespace irr
{
namespace gui
{
class UltraGUIFrame : public IGUIElement
{
friend UltraGUIMenu;
protected:
// Handles mouse input
// NOTE: This may be removed since it seems mostly unnecessary
ICursorControl* cursor;
/* Old size - The previous rectangle of the frame before it is resized
(assuming it is resized) or moved. This is used for resizing and
repositioning the menus. */
recti oldRect;
// Rectangle of the menu bar
recti menuBarRect;
// Rows on the menu bar
irr::u32 menuBarRows;
// Last open x on bar
irr::s32 lastOpenBarX;
// Last occupied location on the bar
// See requestBarSpace and getBarSlotPosition for details
irr::s32 occupiedBarX;
// Last open row
/* This is the first row with a slot available.
NOTE: This is a transient number - it is reset and updated every time
updateAbsolutePosition() is called. */
irr::u32 lastOpenRow;
// ---- For the UltraGUIMenu elements ----
// Left-side menu size
dimension2du leftSideSize;
// Right-side menu size
dimension2du rightSideSize;
// Central window size
dimension2du centerSize;
// Bar icon size
dimension2du barSlotSize;
/* Header bar size - The height of the bar that contains the title
of a menu plus the buttons that control its activity. */
irr::s32 headerHeight;
/* Sprite bank containing the sprites for the menus.
These sprites will be used for when the buttons are hovered over.
The bank is created and stored here (rather than in the menus)
to conserve space. */
IGUISpriteBank* spriteBank;
public:
UltraGUIFrame(
IGUIEnvironment* environment,
ICursorControl* cursorc,
irr::s32 id=-1,
IGUIElement* parent=0,
recti rectangle=recti(0,0,0,0)
);
~UltraGUIFrame(void);
/* Returns a pointer to the environment */
IGUIEnvironment* getEnvironment() const
{
return Environment;
}
/*
Adds a menu to the total.
\param menuID - The ID of the menu being added.
*/
UltraGUIMenu* addMenu(
irr::s32 menuID,
irr::video::ITexture* icon=0
);
/*
Removes a menu whose ID is given. If -1 is given, all menus
are removed.
\param menuID - The ID of the menu being removed.
*/
void removeMenu( irr::s32 menuID );
/*
Closes the menu whose ID is given. The reaction depends on what menu
this is and where it is located.
>> left side menu - Slides left off the screen.
>> right side menu - Slides right off the screen.
>> menu bar menu - Does nothing.
>> central window menu - Disappears.
*/
void closeMenu( irr::s32 menuID );
/*
Closes the menu at the given location
*/
void closeOpenMenuAtLocation( EUltraMenuLocation location );
/*
Opens the menu whose ID is given. The reaction depends on what menu
this is and where it is located.
>> left side menu - Slides right if not open. Otherwise, it is highlighted.
>> right side menu - Slides left if not open. Otherwise, it is highlighted.
>> menu bar menu - Appears as the central window menu, minimizing
any menu that was there already.
>> central window menu - Blinks with a highlighter.
*/
void openMenu( irr::s32 menuID );
/*
Move the menu to the specific location.
*/
void moveMenu( irr::s32 menuID, EUltraMenuLocation location );
/*
Set the menu state. This does everything that the functions
openMenu(), closeMenu(), and moveMenu() do and more.
*/
void setMenuState( irr::s32 menuID, EUltraMenuState state );
/*
Saves a pointer to the requested menu.
Returns true if the menu could be found.
*/
bool getMenu( irr::s32 menuID, UltraGUIMenu*& result );
/*
\param size - The universal size of the left and right side menus.
*/
void setSideMenuSize( dimension2du size );
/*
Sets the bounds for the central window menu.
These are treated as maximum/normal dimensions.
If you wish to treat them as constant, call setCentralWindowMenuSizing()
*/
void setCentralWindowMenuBounds( dimension2du size );
/*
\param size_setting - The new size setting.
Setting one of these may override other, previously-set settings.
*/
//void setCentralWindowMenuSizing( ECWMSize size_setting );
/*
Requests a slot on the menu bar.
This is to ensure that there is available space on the menu bar.
It may require adding another row.
*/
void requestBarSpace( UltraGUIMenu* menu );
/*
Accounts for the given menu leaving the bar.
This allows for other menus to occupy its former location.
*/
void leavingBar( UltraGUIMenu* menu );
/*
Get sprite bank for menus.
This sprite bank contains textures for the menus that will be
used when the menu is hovered over.
*/
IGUISpriteBank* getMenuSpriteBank();
// ---------- Engine stuff ------------
virtual bool OnEvent( const irr::SEvent& event );
virtual void updateAbsolutePosition();
virtual void draw();
/* For any animation of the frame */
virtual void OnPostRender( irr::u32 timeMs );
/* This GUI element is actually determined by what is visible to
the user. Hence, at any given time, whether or not a point is actually
hovering over this frame is determined by the position of the mouse.
For the left, right, and center, whether or not there is a menu being
displayed determines if the mouse is in the frame. On the bottom, there
is a menu bar that always exists. It is this that is checked first. */
virtual bool isPointInside( const vector2di& point ) const;
// ---------- Calculating destinations
/* Returns the position where the lower left corner of the
menu should reside when it is the left-side menu. */
vector2di getLeftSidePosition();
/* Returns the position where the lower right corner of the
menu should reside when it is the right-side menu. */
vector2di getRightSidePosition();
/* Returns the position where the exact center of the menu
should reside when it is the center menu. */
vector2di getCenterCenterPosition();
/* Returns the next open location on the bar where the upper left
corner of the menu should reside when it is a bar icon.
IMPORTANT NOT: This increments the position, and thus it should
not be called by anything but menus that are children of this frame. */
vector2di getBarSlotPosition();
/* Returns the actual available size for the central window menu,
working in cooperation with getCenterCenterPosition() */
dimension2du getCenterWindowSize();
/* Returns the height of the menu bar.
Useful if the implementation of the menu bar ever changes. */
irr::s32 getBarHeight();
// ---------- Drag-to regions
/* Functions that indicate if the mouse is in a region
where a menu can be dragged. The menus themselves will
determine their own sizing, but this ensures that every menu
is just as easy to drag around the screen as every other.
Furthermore, it ensures that screen re-sizing and small screens
can be accounted for. */
bool isInLeftDragRegion( irr::s32 x, irr::s32 y );
bool isInRightDragRegion( irr::s32 x, irr::s32 y );
bool isInCenterDragRegion( irr::s32 x, irr::s32 y );
bool isInBarDragRegion( irr::s32 x, irr::s32 y );
// ---------- Internal stuff -----------
recti getFrameRectChange();
};
}} // end namespace gui and irr
#endif // #ifndef _ULTRAGUIFRAME_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,369 @@
/*
(c) Nicolaus Anderson
*/
#include <irrlicht.h>
#include <IAnimGUIElement.h>
#include "UltraGUIConstants.h"
//#include "EnumCentralWindowMenuSizing.h"
#include "EnumUltraMenuState.h"
#ifndef _ULTRAGUIMENU_
#define _ULTRAGUIMENU_
namespace irr
{
namespace gui
{
class UltraGUIFrame;
//! Class Ultra GUI Menu
/* Container of user-defined GUI elements. */
class UltraGUIMenu : public IAnimGUIElement // IGUIElement
{
friend UltraGUIFrame;
protected:
UltraGUIFrame* ultraframe;
EUltraMenuState menuState;
EUltraMenuLocation menuLocation;
EUltraMenuClose menuCloseSetting;
// Indicates if this object is in transition between two locations
bool inTransition;
// Requested state - what to transition to
EUltraMenuState queuedState;
// Indicates if the state/location/animation should be refreshed.
bool refreshState;
/* Transition speed - The speed at which the menu moves when changing
positions/states. */
irr::f32 transitionSpeed;
/* Transition color - the color of the box representing the menu when
the menu is being relocated. */
irr::video::SColor transitionColor;
// Animator in control of moving this GUI element
IAnimGUIAnimator* moveAnimator;
/* Last time
- The last time OnPostRender was called. This is necessary for finding
the change for the rectangle. */
irr::u32 lastTime;
// Current rectangle of this menu (what is actually drawn)
irr::core::recti currRect;
/* NOTE: The rectangle used by the occupants of this element is
the standard rectangle: AbsoluteRect. AbsoluteRect is NOT used
for the drawing, so we override isPointInside to ensure this
GUI element is brought to the front when clicked.
NOTE: AbsoluteRect MUST be updated after a transition is completed.
*/
/* Rectangle that the menu is trying to become.
This is used for optimization of performance. */
irr::core::recti destinyRect;
// Left-side menu size
irr::core::dimension2du leftSideSize;
// Right-side menu size
irr::core::dimension2du rightSideSize;
// Central window size
irr::core::dimension2du centerSize;
// Bar icon size
irr::core::dimension2du barSlotSize;
// Title text
/* This is displayed on the header bar. */
irr::core::recti titleTextBox;
// Icon to display when the menu is on the bar
irr::video::ITexture* barSprite;
// Should show the bar sprite border
bool hasBarSpriteBorder;
// Colors for the header
irr::video::SColor headerColorTop;
irr::video::SColor headerColorMid;
irr::video::SColor headerColorBottom;
// ---- Buttons ----
IGUIButton* closeButton; /* "Closes" the menu. */
IGUIButton* toLeftButton; /* Sends the menu to the left side.
Not shown when menu is on the left side. */
IGUIButton* toRightButton; /* Sends the menu to the right side.
Not shown when menu is on the right side. */
IGUIButton* toCenterButton; /* Sends the menu to the center area.
Not shown when menu is in the center. */
IGUIButton* minimizeButton; /* Sends the menu to the bar.
Not shown when menu is on the bar. */
irr::core::dimension2du buttonSize;
// ---- OnEvent aspects
bool isSelected;
bool isDragging;
public:
UltraGUIMenu(
UltraGUIFrame* frame,
irr::s32 id,
irr::core::recti rectangle,
irr::io::path resource_path = ULTRAGUI_RESOURCE_PATH
);
~UltraGUIMenu();
/* Returns a pointer to the ultra frame of this menu. */
UltraGUIFrame* getUltraFrame()
{
return ultraframe;
}
/* Returns the menu state of this menu. */
EUltraMenuState getMenuState()
{
return menuState;
}
/* Indicates if the menu is open (not just on the bar). */
bool isTrulyOpen()
{
switch ( menuState )
{
case EUGUIMState_Open: // to be removed?
case EUGUIMState_ToLeft_Open:
case EUGUIMState_ToRight_Open:
case EUGUIMState_ToCenter_Open:
return true;
default:
return false;
}
}
/* Returns the location state of this menu. */
EUltraMenuLocation getMenuLocation()
{
return menuLocation;
}
/* Set the activity for what happens when this menu is told
to close by its button. */
void setCloseButtonAction( EUltraMenuClose action )
{
menuCloseSetting = action;
}
/* Sets the size of the menu rectangle at the appropriate position.
After you set all of the sizes you wish, calld updateAbsolutePosition(). */
void setLeftSize( irr::core::dimension2du size )
{
leftSideSize = size;
}
void setRightSize( irr::core::dimension2du size )
{
rightSideSize = size;
}
void setCenterSize( irr::core::dimension2du size )
{
centerSize = size;
}
/* PLEASE DO NOT USE THIS.
All bars should be kept the same size. This function may be removed
in the near future. */
void setBarSize( irr::core::dimension2du size )
{
barSlotSize = size;
}
/* Gets the size of the menu rectangle at the appropriate position. */
irr::core::dimension2du getLeftSize()
{
return leftSideSize;
}
irr::core::dimension2du getRightSize()
{
return rightSideSize;
}
irr::core::dimension2du getCenterSize()
{
return centerSize;
}
irr::core::dimension2du getBarSize()
{
return barSlotSize;
}
/*
Set the state of the menu.
This determines its open or close state as well as its final location.
It should not matter if you call this function while a menu is in
transition from one location to another.
NOTE: The states of EUGUIMState_Opening and EUGUIMState_Closing are
ignored.
*/
void setMyState( EUltraMenuState state, bool noHighlight=false );
/* Snap-to-state
Immediately brings the menu to the queued state. */
void snapState();
/* Location-from-state
A useful function that converts the state to a location.
*/
EUltraMenuLocation locationFromState( EUltraMenuState state );
/*
Sets the menu bar button sprite.
*/
void setMenuBarSprite( irr::video::ITexture* sprite );
/*
Sets whether there should be a border around the menu bar sprite.
*/
void setBorderOnBarSprite( bool setting )
{
hasBarSpriteBorder = setting;
}
/*
Set menu bar header bar colors for gradient
*/
void setHeaderGradient( irr::video::SColor top, irr::video::SColor mid, irr::video::SColor bottom )
{
headerColorTop = top;
headerColorMid = mid;
headerColorBottom = bottom;
}
// ---------- Engine stuff ------------
virtual bool OnEvent( const irr::SEvent& event );
virtual void draw();
/* For animation of the menu */
virtual void OnPostRender( irr::u32 timeMs );
virtual bool isPointInside( const irr::core::position2di& point ) const;
virtual void updateAbsolutePosition();
/* Overridden to avoid error in the rectangles.
Note that the locations of the rectangles will be determined
by the UltraGUIFrame. */
virtual void setRelativePosition( const irr::core::recti& r ) {}
virtual void setRelativePosition( const irr::core::position2di& position ) {}
// Alias for setting the left and right sizes
virtual void setRelativePositionProportional(const irr::core::rect<f32>& r)
{
//leftSideSize = r.getSize() * ultraframe->getAbsolutePosition().getSize();
//rightSideSize = r.getSize() * ultraframe->getAbsolutePosition().getSize();
}
/* Overridden to avoid error in the rectangles.
Note that the locations of the rectangles will be determined
by the UltraGUIFrame. */
virtual void setAlignment(
EGUI_ALIGNMENT left,
EGUI_ALIGNMENT right,
EGUI_ALIGNMENT top,
EGUI_ALIGNMENT bottom
)
{}
// ----- Internal assistance functions -----
protected:
/* Function that create rectangles based on the proper locations
(as given by UltraGUIFrame) and the designated dimensions. */
irr::core::recti getLeftRectangle();
irr::core::recti getRightRectangle();
irr::core::recti getCenterRectangle();
irr::core::recti getBarRectangle(); /* Should only be called during an update of position. */
irr::core::recti getClosedLeftRectangle();
irr::core::recti getClosedRightRectangle();
irr::core::recti getClosedCenterRectangle();
irr::core::recti getClosedBarRectangle();
/* Function that moves the current rectangle towards a particular
location. */
void moveToQueuedLocation( irr::u32 timeMs );
/* Refreshes the state/location/animation of the menu. */
void refresh();
/* Sets the destination rectangle based on what is queued. */
void setDestinyByQueue();
public:
/* Sets the position and visibility of buttons based on the location
of the menu. */
void refreshButtons();
protected:
/* Sets the relative position of the requested button to the given
rectangle.
\param whichButton - A value between 1 and 4 (inclusive) that gives
the button slot. */
void assignRectToButton( irr::core::recti rectangle, irr::u32 whichButton );
/* Sets the children to visible/enabled */
inline void setChildrenOn( bool setting );
/* For drawing a highlight around the menu.
The menu should glow for a moment and then return to normal.
This requires keeping track of time. */
bool IsHighlighted;
irr::u32 highlightTime;
irr::u32 resetTime; // Time to reset the timer to if the highlighting is reset
irr::video::SColor highlightColor;
// Indicates if the highlighter should be loaded
bool loadHighlight;
// Queues a highlight
inline void queueDrawHighlight( irr::u32 timeMs )
{
resetTime = timeMs;
IsHighlighted = true;
}
inline void resetDrawHighlight()
{
IsHighlighted = false;
highlightTime = 0;
highlightColor.setAlpha(0);
}
public:
//! Is highlighted
/* Indicates if this GUI element will be highlighted if it is
open and the user wants it open. */
bool isHighlighted()
{
return IsHighlighted;
}
};
}} // end namespace gui and irr
#endif // #ifndef _ULTRAGUIMENU_

View File

@ -0,0 +1,31 @@
/*
(c) Nicolaus Anderson
*/
#include "UltraIcon.h"
namespace irr
{
namespace gui
{
UltraIcon::UltraIcon(
IGUIEnvironment* environment,
IGUIElement* parent,
irr::s32 id,
irr::core::recti rectangle
)
: IGUIElement( EGUIET_ELEMENT, environment, parent, id, rectangle )
{
}
UltraIcon::~UltraIcon()
{
}
UltraIcon::shouldShow( bool setting )
{
setVisible( setting );
}
}} // end namespace gui and irr

View File

@ -0,0 +1,53 @@
/*
(c) Nicolaus Anderson
*/
#include <irrlicht.h>
#pragma once
//! Class UltraIcon
/*
This is like a desktop icon.
It should handle the displaying of its text and icon based on the area it is allotted.
*/
class UltraIcon : public IGUIElement, public Searchable
{
public:
UltraIcon(
IGUIEnvironment* environment,
IGUIElement* parent,
irr::s32 id,
irr::core::recti rectangle
);
~UltraIcon();
void setFontSize( irr::s32 size );
void setTextArea( irr::core::dimension2du area );
void setIconArea( irr::core::dimension2du area );
void setText( const wchar_t* text );
void setIconSprite( irr::video::ITexture* sprite );
/* Sets whether the text should be visible or not.
If the text is not visible, the size of the sprite
should be used to determine the bounding box of the element. */
void setTextVisible( bool setting );
/* Sets whether the icon should be visible or not.
If the icon is not visible, the text area should be used
to determine the bounding box of the element. */
void setIconVisible( bool setting );
//! Should show
/* Indicates whether this element should even show up in lists. */
virtual void shouldShow( bool setting );
// ------- Engine stuff ---------
virtual void OnEvent( const irr::SEvent& event );
virtual void draw();
};

View File

@ -0,0 +1,77 @@
/*
(c) Nicolaus Anderson
*/
#include "UltraList.h"
namespace irr
{
namespace gui
{
UltraList::UltraList(
IGUIEnvironment* environment,
IGUIElement* parent,
irr::s32 id,
irr::core::recti rectangle
)
: IGUIElement( EGUIET_ELEMENT, environment, parent, id, rectangle )
{
}
UltraList::~UltraList()
{
}
UltraIcon* UltraList::addListItem( irr::s32 id )
{
UltraIcon* icon = new UltraIcon(EGUIET_ELEMENT,Environment,this,id,iconRect);
Children.push_back((IGUIElement*)icon);
return (IGUIElement*)icon;
}
void UltraList::removeListItem( irr::s32 id )
{
irr::core::list<IGUIElement*>::Iterator i = Children.begin();
for ( ; i != Children.end(); ++i )
{
if ( (*i)->getID() == id )
{
Children.erase(i);
break;
}
}
}
void UltraList::setHorizontalSpacing(irr::s32 gap)
{
xSpacing = gap;
}
void UltraList::setVerticalSpacing(irr::s32 gap)
{
ySpacing = gap;
}
void UltraList::setUniversalSpacing(irr::s32 gap)
{
xSpacing = gap;
ySpacing = gap;
}
void UltraList::OnEvent(const irr::SEvent& event)
{
}
void UltraList::draw()
{
/* Arrange the icons on the basis of what is visible
and how much space there is. */
// Now draw the children
IGUIElement::draw();
}
}} // end namespace gui and irr

View File

@ -0,0 +1,64 @@
/*
(c) Nicolaus Anderson
*/
#include <irrlicht.h>
#include "UltraIcon.h"
#pragma once
namespace irr
{
namespace gui
{
//! Class Ultra List
/*
A list of Ultra Icon GUI elements.
>> It takes into account the sizes of the GUI elements and tries
to list them in such a way that they will fit within either
a specified width (or height) or the parent rectangle.
>> It also allows for searching through elements and displaying
only visible ones.
*/
class UltraList : public IGUIElement
{
protected:
irr::s32 xSpacing;
irr::s32 ySpacing;
public:
UltraList(
IGUIEnvironment* environment,
IGUIElement* parent,
irr::s32 id,
irr::core::recti rectangle
);
~UltraList();
/* Adds an Ultra Icon to the list.
\param id - The ID of the element being added. */
UltraIcon* addListItem( irr::s32 id );
/* Remove an Ultra Icon.
\param id - The ID of the element being added. */
void removeListItem( irr::s32 id );
// Spacing between icons
void setHorizontalSpacing( irr::s32 gap );
void setVerticalSpacing( irr::s32 gap );
void setUniversalSpacing( irr::s32 gap ); // sets both horizontal and vertical
// ------- Engine stuff ---------
virtual void OnEvent( const irr::SEvent& event );
virtual void draw();
/* Hijacking this function - The given child is NOT added because
the only elements wanted in this list are of the type UltraIcon,
and the only way to add them is via addListItem(). */
virtual void addChild( IGUIElement* child ) {}
};
}} // end namespace gui and irr

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,390 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="744.09448819"
height="1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.48.0 r9654"
sodipodi:docname="button.svg"
inkscape:export-filename="C:\Users\Nicolaus Anderson\Desktop\misc\Visual Studio 2008\Projects\UltraGUI\resources\art\minimizeButton.png"
inkscape:export-xdpi="4.1422954"
inkscape:export-ydpi="4.1422954">
<defs
id="defs4">
<linearGradient
id="linearGradient3810">
<stop
style="stop-color:#1f1f1f;stop-opacity:1;"
offset="0"
id="stop3812" />
<stop
id="stop3820"
offset="0.5"
style="stop-color:#6d6d6d;stop-opacity:1;" />
<stop
style="stop-color:#171717;stop-opacity:1;"
offset="1"
id="stop3814" />
</linearGradient>
<linearGradient
id="linearGradient3796">
<stop
id="stop3798"
offset="0"
style="stop-color:#b4b4b4;stop-opacity:1;" />
<stop
style="stop-color:#484848;stop-opacity:1;"
offset="0.20493753"
id="stop3804" />
<stop
id="stop3806"
offset="0.20493753"
style="stop-color:#000000;stop-opacity:1;" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0.81093025"
id="stop3808" />
<stop
id="stop3800"
offset="1"
style="stop-color:#7c7c7c;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3789">
<stop
id="stop3791"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
id="stop3793"
offset="1"
style="stop-color:#ffffff;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3792">
<stop
style="stop-color:#11dfff;stop-opacity:0.14285715;"
offset="0"
id="stop3794" />
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop3796" />
</linearGradient>
<linearGradient
id="linearGradient3784">
<stop
id="stop3786"
offset="0"
style="stop-color:#11dfff;stop-opacity:1;" />
<stop
id="stop3788"
offset="1"
style="stop-color:#ffffff;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3755">
<stop
style="stop-color:#888888;stop-opacity:1;"
offset="0"
id="stop3757" />
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop3759" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3755"
id="linearGradient3761"
x1="357.61664"
y1="404.12994"
x2="357.07217"
y2="714.12994"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.99819004,0,0,1.0640404,0.65321541,-31.720568)" />
<filter
inkscape:collect="always"
id="filter3861">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="9.254206"
id="feGaussianBlur3863" />
</filter>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3789"
id="linearGradient3790"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.99819004,0,0,1.0640404,0.65321541,-31.720568)"
x1="357.61664"
y1="404.12994"
x2="357.07217"
y2="714.12994" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3796"
id="linearGradient3802"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.99819004,0,0,1.0640404,0.65321541,-31.720568)"
x1="357.61664"
y1="404.12994"
x2="357.07217"
y2="714.12994" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3810"
id="linearGradient3818"
x1="145.53685"
y1="394.77084"
x2="143.94952"
y2="730.14148"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.49497475"
inkscape:cx="179.09454"
inkscape:cy="520"
inkscape:document-units="px"
inkscape:current-layer="layer5"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1024"
inkscape:window-height="748"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:snap-global="false" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="back"
inkscape:groupmode="layer"
id="layer1"
style="display:none"
sodipodi:insensitive="true">
<rect
style="color:#000000;fill:url(#linearGradient3761);fill-opacity:1;stroke:#000000;stroke-width:20.6117897;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2985"
width="337.41522"
height="325.51144"
x="192.20824"
y="399.70047"
rx="66.838196"
ry="85.436478" />
</g>
<g
style="display:inline"
id="g3024"
inkscape:groupmode="layer"
inkscape:label="back black"
sodipodi:insensitive="true">
<rect
ry="85.436478"
rx="66.838196"
y="399.70047"
x="192.20824"
height="325.51144"
width="337.41522"
id="rect3026"
style="color:#000000;fill:url(#linearGradient3802);fill-opacity:1;stroke:url(#linearGradient3818);stroke-width:20.6117897;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="x"
sodipodi:insensitive="true"
style="display:none">
<text
xml:space="preserve"
style="font-size:310.62554932px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;filter:url(#filter3861);font-family:Pump Demi Bold LET;-inkscape-font-specification:Pump Demi Bold LET"
x="213.51965"
y="730.54352"
id="text3764-8"
sodipodi:linespacing="125%"
transform="scale(1.1097274,0.9011222)"><tspan
sodipodi:role="line"
id="tspan3766-8"
x="213.51965"
y="730.54352"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#ffffff;fill-opacity:1;font-family:Segoe Script;-inkscape-font-specification:Segoe Script Bold">X</tspan></text>
<text
xml:space="preserve"
style="font-size:267.45251465px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Pump Demi Bold LET;-inkscape-font-specification:Pump Demi Bold LET"
x="226.21634"
y="720.50763"
id="text3764"
sodipodi:linespacing="125%"
transform="scale(1.1201045,0.89277384)"><tspan
sodipodi:role="line"
id="tspan3766"
x="226.21634"
y="720.50763"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Segoe Script;-inkscape-font-specification:Segoe Script">X</tspan></text>
</g>
<g
inkscape:groupmode="layer"
id="layer6"
inkscape:label="new x"
style="display:none"
sodipodi:insensitive="true">
<flowRoot
xml:space="preserve"
id="flowRoot3028"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Pump Demi Bold LET;-inkscape-font-specification:Pump Demi Bold LET"
transform="matrix(26.002054,0,0,19.788226,-6701.8964,-9196.1937)"><flowRegion
id="flowRegion3030"><rect
id="rect3032"
width="20.203047"
height="32.324883"
x="266.68027"
y="482.63614" /></flowRegion><flowPara
id="flowPara3034"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial Bold">x</flowPara></flowRoot> <flowRoot
xml:space="preserve"
id="flowRoot3028-3"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;display:inline;font-family:Pump Demi Bold LET;-inkscape-font-specification:Pump Demi Bold LET"
transform="matrix(16.666348,0,0,13.078395,-4166.9908,-5889.2293)"><flowRegion
id="flowRegion3030-6"><rect
id="rect3032-5"
width="20.203047"
height="32.324883"
x="266.68027"
y="482.63614"
style="fill:#ffffff;fill-opacity:1" /></flowRegion><flowPara
id="flowPara3034-0"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#ffffff;fill-opacity:1;font-family:Arial;-inkscape-font-specification:Arial Bold">x</flowPara></flowRoot> </g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="left arrow"
style="display:none"
sodipodi:insensitive="true">
<path
sodipodi:type="star"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:25;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path2995"
sodipodi:sides="3"
sodipodi:cx="363.65491"
sodipodi:cy="563.44836"
sodipodi:r1="97.729324"
sodipodi:r2="48.243507"
sodipodi:arg1="1.0516502"
sodipodi:arg2="2.0988478"
inkscape:flatsided="false"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 412.14223,648.30118 -72.79487,-43.18053 -73.42081,-42.10744 73.79288,-41.45194 73.17651,-42.53057 -0.998,84.63248 z"
inkscape:transform-center-x="24.243661"
inkscape:transform-center-y="0.21757707"
transform="translate(20.12183,-4.0406102)" />
</g>
<g
style="display:none"
inkscape:label="right arrow"
id="g2997"
inkscape:groupmode="layer"
sodipodi:insensitive="true">
<path
transform="matrix(-1,0,0,1,704.94432,-4.0406102)"
inkscape:transform-center-y="0.21757707"
inkscape:transform-center-x="-24.243661"
d="m 412.14223,648.30118 -72.79487,-43.18053 -73.42081,-42.10744 73.79288,-41.45194 73.17651,-42.53057 -0.998,84.63248 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="2.0988478"
sodipodi:arg1="1.0516502"
sodipodi:r2="48.243507"
sodipodi:r1="97.729324"
sodipodi:cy="563.44836"
sodipodi:cx="363.65491"
sodipodi:sides="3"
id="path2999"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:25;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="star" />
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="center arrow"
style="display:none"
sodipodi:insensitive="true">
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3004"
width="127.27922"
height="117.1777"
x="252.53813"
y="541.22498"
rx="0"
ry="80.294388" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3004-7"
width="127.27922"
height="117.1777"
x="320.21835"
y="472.53464"
rx="0"
ry="80.294388" />
</g>
<g
inkscape:groupmode="layer"
id="layer5"
inkscape:label="to bar arrow"
style="display:inline"
sodipodi:insensitive="true">
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3025"
width="212.61461"
height="55.0308"
x="255.3273"
y="531.89233"
ry="0" />
</g>
<g
style="display:none"
id="g3780"
inkscape:groupmode="layer"
inkscape:label="hover1"
sodipodi:insensitive="true">
<rect
ry="85.436478"
rx="66.838196"
y="399.70047"
x="192.20824"
height="325.51144"
width="337.41522"
id="rect3782"
style="color:#000000;fill:url(#linearGradient3790);fill-opacity:1;stroke:#000000;stroke-width:20.61199951;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

View File

@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="744.09448819"
height="1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.48.0 r9654"
inkscape:export-filename="C:\Users\Nicolaus Anderson\Desktop\misc\irrlicht extensions\UltraGUI\resources\art\newfile.png"
inkscape:export-xdpi="4.1422954"
inkscape:export-ydpi="4.1422954"
sodipodi:docname="New document 1">
<defs
id="defs4">
<linearGradient
id="linearGradient3853">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop3855" />
<stop
style="stop-color:#d2f5ff;stop-opacity:1;"
offset="1"
id="stop3857" />
</linearGradient>
<linearGradient
id="linearGradient3837">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3839" />
<stop
style="stop-color:#d6d6d6;stop-opacity:1;"
offset="1"
id="stop3841" />
</linearGradient>
<linearGradient
id="linearGradient3829">
<stop
id="stop3831"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
id="stop3833"
offset="1"
style="stop-color:#e2e2e2;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3813">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3815" />
<stop
style="stop-color:#2b2b2b;stop-opacity:1;"
offset="1"
id="stop3817" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3813"
id="linearGradient3819"
x1="259.28571"
y1="517.00504"
x2="499.28571"
y2="517.00504"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3837"
id="linearGradient3843"
x1="316.42857"
y1="530.97696"
x2="447.85714"
y2="530.97696"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.0875"
inkscape:cx="400.519"
inkscape:cy="520"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-grids="false"
inkscape:snap-to-guides="false"
inkscape:snap-global="false"
inkscape:window-width="1024"
inkscape:window-height="748"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:#000000;stroke-width:10.23048019;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 265.11524,476.53265 74.63762,-0.73191 c 0,0 5.83668,-2.37334 10.2142,-6.76483 5.15894,-5.1754 6.0137,-12.01379 6.0137,-12.01379 l 0.33257,-89.5447 z"
id="path2987-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsccc" />
<path
style="fill:none;stroke:#000000;stroke-width:10.2388258;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 264.07644,476.41244 0,196.11372 236.23507,0 -0.73364,-305.47082 -143.06163,0 z"
id="path2985-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
style="fill:#ffffff;stroke:url(#linearGradient3819);stroke-width:20;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;fill-opacity:1"
d="m 264.28571,474.50504 0,192.14286 230,0 -0.71428,-299.28572 -139.28572,0 z"
id="path2985"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
style="fill:none;stroke:#000000;stroke-width:20;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 265,473.79075 73.07251,-0.71428 c 0,0 5.71429,-2.31618 10.00001,-6.6019 5.05076,-5.05075 5.8876,-11.72443 5.8876,-11.72443 l 0.32559,-87.38796 z"
id="path2987"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

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