Show how to modify cursors and offer some useful tool-functions for creating cursors. It can also be used for experiments with the mouse in general.
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#endif
const int DELAY_TIME = 3000;
enum ETimerAction
{
ETA_MOUSE_VISIBLE,
ETA_MOUSE_INVISIBLE,
};
Structure to allow delayed execution of some actions.
struct TimerAction
{
ETimerAction Action;
};
struct SAppContext
{
SAppContext()
: Device(0), InfoStatic(0), EventBox(0), CursorBox(0), SpriteBox(0)
, ButtonSetVisible(0), ButtonSetInvisible(0), ButtonSimulateBadFps(0)
, ButtonChangeIcon(0)
, SimulateBadFps(false)
{
}
void update()
{
if (!Device)
return;
for (
u32 i=0; i < TimerActions.size(); ++i )
{
if ( timeNow >= TimerActions[i].TargetTime )
{
runTimerAction(TimerActions[i]);
TimerActions.erase(i);
}
else
{
++i;
}
}
}
void runTimerAction(const TimerAction& action)
{
if (ETA_MOUSE_VISIBLE == action.Action)
{
ButtonSetVisible->setEnabled(true);
}
else if ( ETA_MOUSE_INVISIBLE == action.Action)
{
ButtonSetInvisible->setEnabled(true);
}
}
Add another icon which the user can click and select as cursor later on.
void addIcon(
const stringw& name,
const SCursorSprite &sprite,
bool addCursor=
true)
{
SpriteBox->addItem(name.c_str(), sprite.SpriteId);
Sprites.push_back(sprite);
if ( addCursor )
{
Here we create a hardware cursor from a sprite
CursorBox->addItem(name.c_str());
}
}
IrrlichtDevice * Device;
gui::IGUIStaticText * InfoStatic;
gui::IGUIListBox * EventBox;
gui::IGUIListBox * CursorBox;
gui::IGUIListBox * SpriteBox;
gui::IGUIButton * ButtonSetVisible;
gui::IGUIButton * ButtonSetInvisible;
gui::IGUIButton * ButtonSimulateBadFps;
gui::IGUIButton * ButtonChangeIcon;
array<TimerAction> TimerActions;
bool SimulateBadFps;
array<SCursorSprite> Sprites;
};
Helper function to print mouse event names into a stringw
void PrintMouseEventName(
const SEvent& event,
stringw &result)
{
switch ( event.MouseInput.Event )
{
default:
break;
}
}
Helper function to print all the state information which get from a mouse-event into a stringw
void PrintMouseState(
const SEvent& event,
stringw &result)
{
result +=
stringw(event.MouseInput.X);
result +=
stringw(event.MouseInput.Y);
result +=
stringw(event.MouseInput.Wheel);
if ( event.MouseInput.Shift )
else
if ( event.MouseInput.Control )
else
result +=
stringw(L
"ButtonStates: ");
result +=
stringw(event.MouseInput.ButtonStates);
result +=
stringw(L
"isLeftPressed: ");
if ( event.MouseInput.isLeftPressed() )
else
result +=
stringw(L
"isRightPressed: ");
if ( event.MouseInput.isRightPressed() )
else
result +=
stringw(L
"isMiddlePressed: ");
if ( event.MouseInput.isMiddlePressed() )
else
PrintMouseEventName(event, result);
}
A typical event receiver.
class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver(SAppContext & context) : Context(context) { }
virtual bool OnEvent(const SEvent& event)
{
{
switch ( event.GUIEvent.EventType )
{
{
u32 timeNow = Context.Device->getTimer()->getTime();
TimerAction action;
action.TargetTime = timeNow + DELAY_TIME;
if ( event.GUIEvent.Caller == Context.ButtonSetVisible )
{
action.Action = ETA_MOUSE_VISIBLE;
Context.TimerActions.push_back(action);
Context.ButtonSetVisible->setEnabled(false);
}
else if ( event.GUIEvent.Caller == Context.ButtonSetInvisible )
{
action.Action = ETA_MOUSE_INVISIBLE;
Context.TimerActions.push_back(action);
Context.ButtonSetInvisible->setEnabled(false);
}
else if ( event.GUIEvent.Caller == Context.ButtonSimulateBadFps )
{
Context.SimulateBadFps = Context.ButtonSimulateBadFps->isPressed();
}
else if ( event.GUIEvent.Caller == Context.ButtonChangeIcon )
{
Replace an existing cursor icon by another icon. The user has to select both - the icon which should be replaced and the icon which will replace it.
s32 selectedCursor = Context.CursorBox->getSelected();
s32 selectedSprite = Context.SpriteBox->getSelected();
if ( selectedCursor >= 0 && selectedSprite >= 0 )
{
This does replace the icon.
Context.Device->getCursorControl()->changeIcon((
ECURSOR_ICON)selectedCursor, Context.Sprites[selectedSprite] );
Do also show the new icon.
Context.Device->getCursorControl()->setActiveIcon(
ECURSOR_ICON(selectedCursor) );
}
}
}
break;
{
if ( event.GUIEvent.Caller == Context.CursorBox )
{
Find out which cursor the user selected
s32 selected = Context.CursorBox->getSelected();
if ( selected >= 0 )
{
Here we set the new cursor icon which will now be used within our window.
Context.Device->getCursorControl()->setActiveIcon(
ECURSOR_ICON(selected) );
}
}
}
break;
default:
break;
}
}
{
PrintMouseState(event, infoText);
Context.InfoStatic->setText(infoText.c_str());
{
infoText = L"";
PrintMouseEventName(event, infoText);
Context.EventBox->insertItem(0, infoText.c_str(), -1);
}
}
return false;
}
private:
SAppContext & Context;
};
Use several imagefiles as animation frames for a sprite which can be used as cursor icon. The images in those files all need to have the same size. Return sprite index on success or -1 on failure
s32 AddAnimatedIconToSpriteBank( gui::IGUISpriteBank * spriteBank, video::IVideoDriver* driver,
const array< io::path >& files,
u32 frameTime )
{
if ( !spriteBank || !driver || !files.size() )
return -1;
video::ITexture * tex = driver->getTexture( files[0] );
if ( tex )
{
array< rect<s32> >& spritePositions = spriteBank->getPositions();
u32 idxRect = spritePositions.size();
spritePositions.push_back( rect<s32>(0,0, tex->getSize().Width, tex->getSize().Height) );
SGUISprite sprite;
sprite.frameTime = frameTime;
array< SGUISprite >& sprites = spriteBank->getSprites();
u32 startIdx = spriteBank->getTextureCount();
for (
u32 f=0; f < files.size(); ++f )
{
tex = driver->getTexture( files[f] );
if ( tex )
{
spriteBank->addTexture( driver->getTexture(files[f]) );
gui::SGUISpriteFrame frame;
frame.rectNumber = idxRect;
frame.textureNumber = startIdx+f;
sprite.Frames.push_back( frame );
}
}
sprites.push_back( sprite );
return sprites.size()-1;
}
return -1;
}
Use several images within one imagefile as animation frames for a sprite which can be used as cursor icon The sizes of the icons within that file all need to have the same size Return sprite index on success or -1 on failure
s32 AddAnimatedIconToSpriteBank( gui::IGUISpriteBank * spriteBank, video::IVideoDriver* driver,
const io::path& file,
const array< rect<s32> >& rects,
u32 frameTime )
{
if ( !spriteBank || !driver || !rects.size() )
return -1;
video::ITexture * tex = driver->getTexture( file );
if ( tex )
{
array< rect<s32> >& spritePositions = spriteBank->getPositions();
u32 idxRect = spritePositions.size();
u32 idxTex = spriteBank->getTextureCount();
spriteBank->addTexture( tex );
SGUISprite sprite;
sprite.frameTime = frameTime;
array< SGUISprite >& sprites = spriteBank->getSprites();
for (
u32 i=0; i < rects.size(); ++i )
{
spritePositions.push_back( rects[i] );
gui::SGUISpriteFrame frame;
frame.rectNumber = idxRect+i;
frame.textureNumber = idxTex;
sprite.Frames.push_back( frame );
}
sprites.push_back( sprite );
return sprites.size()-1;
}
return -1;
}
Create a non-animated icon from the given file and position and put it into the spritebank. We can use this icon later on in a cursor.
s32 AddIconToSpriteBank( gui::IGUISpriteBank * spriteBank, video::IVideoDriver* driver,
const io::path& file,
const core::rect<s32>& rect )
{
if ( !spriteBank || !driver )
return -1;
video::ITexture * tex = driver->getTexture( file );
if ( tex )
{
core::array< core::rect<irr::s32> >& spritePositions = spriteBank->getPositions();
spritePositions.push_back( rect );
array< SGUISprite >& sprites = spriteBank->getSprites();
spriteBank->addTexture( tex );
gui::SGUISpriteFrame frame;
frame.rectNumber = spritePositions.size()-1;
frame.textureNumber = spriteBank->getTextureCount()-1;
SGUISprite sprite;
sprite.frameTime = 0;
sprite.Frames.push_back( frame );
sprites.push_back( sprite );
return sprites.size()-1;
}
return -1;
}
int main()
{
return 1;
IrrlichtDevice * device =
createDevice(driverType, dimension2d<u32>(640, 480));
if (device == 0)
return 1;
device->setResizable(true);
device->setWindowCaption(L"Cursor control - Irrlicht engine tutorial");
video::IVideoDriver* driver = device->getVideoDriver();
IGUIEnvironment* env = device->getGUIEnvironment();
gui::IGUISpriteBank * SpriteBankIcons;
SAppContext context;
context.Device = device;
env->addStaticText (L"Cursor state information", rectInfoStatic, true, true);
context.InfoStatic = env->addStaticText (L"", rectInfoStatic, true, true);
env->addStaticText (L"click events (new on top)", rectEventBox, true, true);
context.EventBox = env->addListBox(rectEventBox);
env->addStaticText (L"cursors, click to set the active one", rectCursorBox, true, true);
context.CursorBox = env->addListBox(rectCursorBox);
env->addStaticText (L"sprites", rectSpriteBox, true, true);
context.SpriteBox = env->addListBox(rectSpriteBox);
context.ButtonSetVisible = env->addButton( rect<s32>( 410, 20, 560, 40 ), 0, -1, L"set visible (delayed)" );
context.ButtonSetInvisible = env->addButton( rect<s32>( 410, 50, 560, 70 ), 0, -1, L"set invisible (delayed)" );
context.ButtonSimulateBadFps = env->addButton( rect<s32>( 410, 80, 560, 100 ), 0, -1, L"simulate bad FPS" );
context.ButtonSimulateBadFps->setIsPushButton(true);
context.ButtonChangeIcon = env->addButton( rect<s32>( 410, 140, 560, 160 ), 0, -1, L"replace cursor icon\n(cursor+sprite must be selected)" );
{
}
Create sprites which then can be used as cursor icons.
SpriteBankIcons = env->addEmptySpriteBank(
io::path(
"cursor_icons"));
context.SpriteBox->setSpriteBank(SpriteBankIcons);
array< io::path > files;
files.push_back(
io::path(
"../../media/icon_crosshairs16x16bw1.png") );
files.push_back(
io::path(
"../../media/icon_crosshairs16x16bw2.png") );
files.push_back(
io::path(
"../../media/icon_crosshairs16x16bw3.png") );
files.push_back(
io::path(
"../../media/icon_crosshairs16x16bw3.png") );
files.push_back(
io::path(
"../../media/icon_crosshairs16x16bw2.png") );
SCursorSprite spriteBw;
spriteBw.SpriteId = AddAnimatedIconToSpriteBank( SpriteBankIcons, driver, files, 200 );
spriteBw.SpriteBank = SpriteBankIcons;
spriteBw.HotSpot = position2d<s32>(7,7);
context.addIcon(L"crosshair_bw", spriteBw);
array< rect<s32> > iconRects;
iconRects.push_back( rect<s32>(0,0, 16, 16) );
iconRects.push_back( rect<s32>(16,0, 32, 16) );
iconRects.push_back( rect<s32>(0,16, 16, 32) );
iconRects.push_back( rect<s32>(0,16, 16, 32) );
iconRects.push_back( rect<s32>(16,0, 32, 16) );
SCursorSprite spriteCol;
spriteCol.SpriteId = AddAnimatedIconToSpriteBank( SpriteBankIcons, driver,
io::path(
"../../media/icon_crosshairs16x16col.png"), iconRects, 200 );
spriteCol.HotSpot = position2d<s32>(7,7);
spriteCol.SpriteBank = SpriteBankIcons;
context.addIcon(L"crosshair_colored", spriteCol);
rect<s32> rectIcon;
SCursorSprite spriteNonAnimated(SpriteBankIcons, 0, position2d<s32>(7,7));
rectIcon = rect<s32>(0,0, 16, 16);
spriteNonAnimated.SpriteId = AddIconToSpriteBank( SpriteBankIcons, driver,
io::path(
"../../media/icon_crosshairs16x16col.png"), rectIcon );
context.addIcon(L"crosshair_col1", spriteNonAnimated, false);
rectIcon = rect<s32>(16,0, 32, 16);
spriteNonAnimated.SpriteId = AddIconToSpriteBank( SpriteBankIcons, driver,
io::path(
"../../media/icon_crosshairs16x16col.png"), rectIcon );
context.addIcon(L"crosshair_col2", spriteNonAnimated, false);
rectIcon = rect<s32>(0,16, 16, 32);
spriteNonAnimated.SpriteId = AddIconToSpriteBank( SpriteBankIcons, driver,
io::path(
"../../media/icon_crosshairs16x16col.png"), rectIcon );
context.addIcon(L"crosshair_col3", spriteNonAnimated, false);
MyEventReceiver receiver(context);
device->setEventReceiver(&receiver);
while(device->run() && driver)
{
{
u32 realTimeNow = device->getTimer()->getRealTime();
context.update();
driver->beginScene(true, true, SColor(0,200,200,200));
env->drawAll();
if ( context.SpriteBox )
{
s32 selectedSprite = context.SpriteBox->getSelected();
if ( selectedSprite >= 0 && context.Sprites[selectedSprite].SpriteId >= 0 )
{
SpriteBankIcons->draw2DSprite(
u32(context.Sprites[selectedSprite].SpriteId),
position2di(580, 140), 0, video::SColor(255, 255, 255, 255), 0, realTimeNow);
}
}
driver->endScene();
}
if ( context.SimulateBadFps )
{
device->sleep(500);
}
else
{
device->sleep(10);
}
}
device->drop();
return 0;
}