123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578 |
- /** Example 024 CursorControl
- 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.
- */
- #include <irrlicht.h>
- #include "driverChoice.h"
- #include "exampleHelper.h"
- using namespace irr;
- using namespace core;
- using namespace scene;
- using namespace video;
- using namespace io;
- using namespace gui;
- #ifdef _MSC_VER
- #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
- {
- u32 TargetTime;
- 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;
- u32 timeNow = Device->getTimer()->getTime();
- 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)
- {
- Device->getCursorControl()->setVisible(true);
- ButtonSetVisible->setEnabled(true);
- }
- else if ( ETA_MOUSE_INVISIBLE == action.Action)
- {
- Device->getCursorControl()->setVisible(false);
- 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)
- {
- // Sprites are just icons - not yet cursors. They can be displayed by Irrlicht sprite functions and be used to create cursors.
- SpriteBox->addItem(name.c_str(), sprite.SpriteId);
- Sprites.push_back(sprite);
- // create the cursor together with the icon?
- if ( addCursor )
- {
- /* Here we create a hardware cursor from a sprite */
- Device->getCursorControl()->addIcon(sprite);
- // ... and add it to the cursors selection listbox to the other system cursors.
- 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 )
- {
- case EMIE_LMOUSE_PRESSED_DOWN: result += stringw(L"EMIE_LMOUSE_PRESSED_DOWN"); break;
- case EMIE_RMOUSE_PRESSED_DOWN: result += stringw(L"EMIE_RMOUSE_PRESSED_DOWN"); break;
- case EMIE_MMOUSE_PRESSED_DOWN: result += stringw(L"EMIE_MMOUSE_PRESSED_DOWN"); break;
- case EMIE_LMOUSE_LEFT_UP: result += stringw(L"EMIE_LMOUSE_LEFT_UP"); break;
- case EMIE_RMOUSE_LEFT_UP: result += stringw(L"EMIE_RMOUSE_LEFT_UP"); break;
- case EMIE_MMOUSE_LEFT_UP: result += stringw(L"EMIE_MMOUSE_LEFT_UP"); break;
- case EMIE_MOUSE_MOVED: result += stringw(L"EMIE_MOUSE_MOVED"); break;
- case EMIE_MOUSE_WHEEL: result += stringw(L"EMIE_MOUSE_WHEEL"); break;
- case EMIE_LMOUSE_DOUBLE_CLICK: result += stringw(L"EMIE_LMOUSE_DOUBLE_CLICK"); break;
- case EMIE_RMOUSE_DOUBLE_CLICK: result += stringw(L"EMIE_RMOUSE_DOUBLE_CLICK"); break;
- case EMIE_MMOUSE_DOUBLE_CLICK: result += stringw(L"EMIE_MMOUSE_DOUBLE_CLICK"); break;
- case EMIE_LMOUSE_TRIPLE_CLICK: result += stringw(L"EMIE_LMOUSE_TRIPLE_CLICK"); break;
- case EMIE_RMOUSE_TRIPLE_CLICK: result += stringw(L"EMIE_RMOUSE_TRIPLE_CLICK"); break;
- case EMIE_MMOUSE_TRIPLE_CLICK: result += stringw(L"EMIE_MMOUSE_TRIPLE_CLICK"); break;
- default:
- break;
- }
- }
- /*
- Helper function to print all the state information from a mouse event into a stringw
- */
- void PrintMouseState(const SEvent& event, stringw &result)
- {
- result += stringw(L"X: ");
- result += stringw(event.MouseInput.X);
- result += stringw(L"\n");
- result += stringw(L"Y: ");
- result += stringw(event.MouseInput.Y);
- result += stringw(L"\n");
- result += stringw(L"Wheel: ");
- result += stringw(event.MouseInput.Wheel);
- result += stringw(L"\n");
- result += stringw(L"Shift: ");
- if ( event.MouseInput.Shift )
- result += stringw(L"true\n");
- else
- result += stringw(L"false\n");
- result += stringw(L"Control: ");
- if ( event.MouseInput.Control )
- result += stringw(L"true\n");
- else
- result += stringw(L"false\n");
- result += stringw(L"ButtonStates: ");
- result += stringw(event.MouseInput.ButtonStates);
- result += stringw(L"\n");
- result += stringw(L"isLeftPressed: ");
- if ( event.MouseInput.isLeftPressed() )
- result += stringw(L"true\n");
- else
- result += stringw(L"false\n");
- result += stringw(L"isRightPressed: ");
- if ( event.MouseInput.isRightPressed() )
- result += stringw(L"true\n");
- else
- result += stringw(L"false\n");
- result += stringw(L"isMiddlePressed: ");
- if ( event.MouseInput.isMiddlePressed() )
- result += stringw(L"true\n");
- else
- result += stringw(L"false\n");
- result += stringw(L"Event: ");
- PrintMouseEventName(event, result);
- result += stringw(L"\n");
- }
- /*
- A typical event receiver.
- */
- class MyEventReceiver : public IEventReceiver
- {
- public:
- MyEventReceiver(SAppContext & context) : Context(context) { }
- virtual bool OnEvent(const SEvent& event)
- {
- if (event.EventType == EET_GUI_EVENT )
- {
- switch ( event.GUIEvent.EventType )
- {
- case EGET_BUTTON_CLICKED:
- {
- 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;
- case EGET_LISTBOX_CHANGED:
- case EGET_LISTBOX_SELECTED_AGAIN:
- {
- 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;
- }
- }
- if (event.EventType == EET_MOUSE_INPUT_EVENT)
- {
- stringw infoText;
- PrintMouseState(event, infoText);
- Context.InfoStatic->setText(infoText.c_str());
- if ( event.MouseInput.Event != EMIE_MOUSE_MOVED && event.MouseInput.Event != EMIE_MOUSE_WHEEL ) // no spam
- {
- infoText = L"";
- PrintMouseEventName(event, infoText);
- Context.EventBox->insertItem(0, infoText.c_str(), -1);
- }
- }
- if ( event.EventType == EET_KEY_INPUT_EVENT)
- {
- // Allow invisible cursor to show up again when users presses ESC
- if ( !event.KeyInput.PressedDown && event.KeyInput.Key == irr::KEY_ESCAPE )
- {
- TimerAction action;
- action.Action = ETA_MOUSE_VISIBLE;
- Context.runTimerAction(action);
- }
- }
- return false;
- }
- private:
- SAppContext & Context;
- };
- /*
- Use several image files as animation frames for a sprite which can then be used as a 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 image file as animation frames for a sprite which can then be used as a 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()
- {
- video::E_DRIVER_TYPE driverType = driverChoiceConsole();
- if (driverType==video::EDT_COUNT)
- return 1;
- IrrlichtDevice * device = createDevice(driverType, dimension2d<u32>(640, 480));
- if (device == 0)
- return 1; // could not create selected driver.
- // It's sometimes of interest to know how the mouse behaves after a resize
- device->setResizable(true);
- device->setWindowCaption(L"Cursor control - Irrlicht engine tutorial");
- video::IVideoDriver* driver = device->getVideoDriver();
- IGUIEnvironment* env = device->getGUIEnvironment();
- SAppContext context;
- context.Device = device;
- rect< s32 > rectInfoStatic(10,10, 200, 200);
- env->addStaticText (L"Cursor state information", rectInfoStatic, true, true);
- rectInfoStatic.UpperLeftCorner += dimension2di(0, 15);
- context.InfoStatic = env->addStaticText (L"", rectInfoStatic, true, true);
- rect< s32 > rectEventBox(10,210, 200, 400);
- env->addStaticText (L"Click events (new on top)", rectEventBox, true, true);
- rectEventBox.UpperLeftCorner += dimension2di(0, 15);
- context.EventBox = env->addListBox(rectEventBox);
- rect< s32 > rectCursorBox(210,10, 400, 250);
- env->addStaticText (L"Cursors, click to set the active one", rectCursorBox, true, true);
- rectCursorBox.UpperLeftCorner += dimension2di(0, 15);
- context.CursorBox = env->addListBox(rectCursorBox);
- rect< s32 > rectSpriteBox(210,260, 400, 400);
- env->addStaticText (L"Sprites", rectSpriteBox, true, true);
- rectSpriteBox.UpperLeftCorner += dimension2di(0, 15);
- 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);
- s32 t = context.SpriteBox->getAbsolutePosition().UpperLeftCorner.Y;
- context.ButtonChangeIcon = env->addButton( rect<s32>( 410, t, 560, t+20), 0, -1, L"Replace cursor icon\n(cursor+sprite must be selected)" );
- // set the names for all the system cursors
- for ( int i=0; i < (int)gui::ECI_COUNT; ++i )
- {
- context.CursorBox->addItem(stringw( GUICursorIconNames[i] ).c_str());
- }
- /*
- Create sprites which then can be used as cursor icons.
- */
- gui::IGUISpriteBank * SpriteBankIcons = env->addEmptySpriteBank(io::path("cursor_icons"));
- context.SpriteBox->setSpriteBank(SpriteBankIcons);
- const io::path mediaPath = getExampleMediaPath();
- // create one animated icon from several files
- array< io::path > files;
- files.push_back( io::path(mediaPath + "icon_crosshairs16x16bw1.png") );
- files.push_back( io::path(mediaPath + "icon_crosshairs16x16bw2.png") );
- files.push_back( io::path(mediaPath + "icon_crosshairs16x16bw3.png") );
- files.push_back( io::path(mediaPath + "icon_crosshairs16x16bw3.png") );
- files.push_back( io::path(mediaPath + "icon_crosshairs16x16bw2.png") );
- SCursorSprite spriteBw; // the sprite + some additional information needed for cursors
- spriteBw.SpriteId = AddAnimatedIconToSpriteBank( SpriteBankIcons, driver, files, 200 );
- spriteBw.SpriteBank = SpriteBankIcons;
- spriteBw.HotSpot = position2d<s32>(7,7);
- context.addIcon(L"crosshair_bw", spriteBw);
- // create one animated icon from one file
- 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; // the sprite + some additional information needed for cursors
- spriteCol.SpriteId = AddAnimatedIconToSpriteBank( SpriteBankIcons, driver, io::path(mediaPath + "icon_crosshairs16x16col.png"), iconRects, 200 );
- spriteCol.HotSpot = position2d<s32>(7,7);
- spriteCol.SpriteBank = SpriteBankIcons;
- context.addIcon(L"crosshair_colored", spriteCol);
- // Create some non-animated icons
- 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(mediaPath + "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(mediaPath + "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(mediaPath + "icon_crosshairs16x16col.png"), rectIcon );
- context.addIcon(L"crosshair_col3", spriteNonAnimated, false);
- MyEventReceiver receiver(context);
- device->setEventReceiver(&receiver);
- while(device->run() && driver)
- {
- // if (device->isWindowActive())
- {
- u32 realTimeNow = device->getTimer()->getRealTime();
- context.update();
- driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(0,200,200,200));
- env->drawAll();
- // draw custom sprite with Irrlicht functions for comparison. It should usually look the same as the cursors.
- 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();
- }
- // By simulating a bad frame rate we can find out if hardware support for cursors works or not.
- // If it works the cursor will move as usual, otherwise it will update with only 2 fps when SimulateBadFps is true.
- if ( context.SimulateBadFps )
- {
- device->sleep(500); // 2 fps
- }
- else
- {
- device->yield(); // be nice
- }
- }
- device->drop();
- return 0;
- }
- /*
- **/
|