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 |