Finish the project! Added GUI menu for setting the parameters values
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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).
|
|
@ -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_
|
|
@ -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__
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
|
||||
}}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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_
|
|
@ -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_
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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_
|
|
@ -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__
|
|
@ -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__
|
After Width: | Height: | Size: 93 KiB |
After Width: | Height: | Size: 112 KiB |
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
};
|
|
@ -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
|
||||
};
|
|
@ -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 )
|
||||
{
|
||||
}
|
|
@ -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 );
|
||||
};
|
|
@ -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
|
|
@ -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
|
|
@ -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_
|
|
@ -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_
|
|
@ -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
|
|
@ -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();
|
||||
};
|
|
@ -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
|
|
@ -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
|
After Width: | Height: | Size: 16 KiB |
|
@ -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 |
After Width: | Height: | Size: 707 B |
After Width: | Height: | Size: 408 B |
After Width: | Height: | Size: 450 B |
After Width: | Height: | Size: 478 B |
After Width: | Height: | Size: 463 B |
After Width: | Height: | Size: 369 B |
After Width: | Height: | Size: 393 B |
After Width: | Height: | Size: 422 B |
After Width: | Height: | Size: 412 B |
After Width: | Height: | Size: 558 B |
After Width: | Height: | Size: 358 B |
|
@ -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 |
After Width: | Height: | Size: 751 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 598 B |
After Width: | Height: | Size: 482 B |
After Width: | Height: | Size: 562 B |
After Width: | Height: | Size: 573 B |
After Width: | Height: | Size: 571 B |
After Width: | Height: | Size: 620 B |
After Width: | Height: | Size: 498 B |
After Width: | Height: | Size: 577 B |
After Width: | Height: | Size: 604 B |
After Width: | Height: | Size: 617 B |
After Width: | Height: | Size: 642 B |
After Width: | Height: | Size: 656 B |
After Width: | Height: | Size: 638 B |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 48 KiB |