Przeglądaj źródła

Added getComponentTypes() function to component factories & Scene.
Added unhandled key event also to LineEdit.
Added Console command history.
Fixed scanDirectory() returning full path for directories.
Code cleanup.

Lasse Öörni 15 lat temu
rodzic
commit
97370cc707
42 zmienionych plików z 231 dodań i 113 usunięć
  1. 7 0
      Engine/Audio/AudioComponentFactory.cpp
  2. 2 0
      Engine/Audio/AudioComponentFactory.h
  3. 1 1
      Engine/Common/File.cpp
  4. 71 5
      Engine/Engine/Console.cpp
  5. 18 2
      Engine/Engine/Console.h
  6. 7 0
      Engine/Engine/EngineComponentFactory.cpp
  7. 2 0
      Engine/Engine/EngineComponentFactory.h
  8. 2 2
      Engine/Engine/RegisterCommon.cpp
  9. 4 1
      Engine/Engine/RegisterEngine.cpp
  10. 8 0
      Engine/Engine/RegisterScene.cpp
  11. 1 4
      Engine/Network/Network.cpp
  12. 6 0
      Engine/Physics/PhysicsComponentFactory.cpp
  13. 2 0
      Engine/Physics/PhysicsComponentFactory.h
  14. 2 7
      Engine/Renderer/AnimatedModel.cpp
  15. 1 4
      Engine/Renderer/Animation.cpp
  16. 1 4
      Engine/Renderer/BillboardSet.cpp
  17. 2 8
      Engine/Renderer/CustomObject.cpp
  18. 2 8
      Engine/Renderer/Geometry.cpp
  19. 2 8
      Engine/Renderer/InstancedModel.cpp
  20. 1 4
      Engine/Renderer/Material.cpp
  21. 2 6
      Engine/Renderer/Model.cpp
  22. 2 6
      Engine/Renderer/Pipeline.cpp
  23. 4 16
      Engine/Renderer/Renderer.cpp
  24. 14 0
      Engine/Renderer/RendererComponentFactory.cpp
  25. 2 0
      Engine/Renderer/RendererComponentFactory.h
  26. 1 4
      Engine/Renderer/Skeleton.cpp
  27. 1 4
      Engine/Renderer/StaticModel.cpp
  28. 5 0
      Engine/Scene/BaseComponentFactory.cpp
  29. 2 0
      Engine/Scene/BaseComponentFactory.h
  30. 2 0
      Engine/Scene/ComponentFactory.h
  31. 1 4
      Engine/Scene/Node.cpp
  32. 9 2
      Engine/Scene/Scene.cpp
  33. 2 0
      Engine/Scene/Scene.h
  34. 5 0
      Engine/Script/ScriptComponentFactory.cpp
  35. 2 0
      Engine/Script/ScriptComponentFactory.h
  36. 2 2
      Engine/UI/FileSelector.cpp
  37. 18 3
      Engine/UI/LineEdit.cpp
  38. 2 2
      Engine/UI/ListView.cpp
  39. 1 4
      Engine/UI/UIElement.cpp
  40. 2 2
      Engine/UI/UIEvents.h
  41. 9 0
      Examples/NinjaSnowWar/GameObjectFactory.cpp
  42. 1 0
      Examples/NinjaSnowWar/GameObjectFactory.h

+ 7 - 0
Engine/Audio/AudioComponentFactory.cpp

@@ -38,8 +38,15 @@ Component* AudioComponentFactory::createComponent(ShortStringHash type, const st
 {
     if (type == StereoChannel::getTypeStatic())
         return new StereoChannel(mAudio, name);
+    
     if (type == PositionalChannel::getTypeStatic())
         return new PositionalChannel(mAudio, name);
     
     return 0;
 }
+
+void AudioComponentFactory::getComponentTypes(std::vector<std::string>& dest)
+{
+    dest.push_back(StereoChannel::getTypeNameStatic());
+    dest.push_back(PositionalChannel::getTypeNameStatic());
+}

+ 2 - 0
Engine/Audio/AudioComponentFactory.h

@@ -38,6 +38,8 @@ public:
     
     //! Create a component of the specified type. Return null if can not create
     virtual Component* createComponent(ShortStringHash type, const std::string& name = std::string());
+    //! Return type names of components that can be created
+    virtual void getComponentTypes(std::vector<std::string>& dest);
     
 private:
     //! Audio subsystem

+ 1 - 1
Engine/Common/File.cpp

@@ -404,7 +404,7 @@ void scanDirectoryInternal(std::vector<std::string>& result, std::string path, c
                 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                 {
                     if (flags & SCAN_DIRECTORIES)
-                        result.push_back(path + fileName);
+                        result.push_back(deltaPath + fileName);
                     if ((recursive) && (fileName != ".") && (fileName != ".."))
                         scanDirectoryInternal(result, path + fileName, startPath, filter, flags, recursive);
                 }

+ 71 - 5
Engine/Engine/Console.cpp

@@ -25,6 +25,7 @@
 #include "Console.h"
 #include "Engine.h"
 #include "Font.h"
+#include "InputEvents.h"
 #include "LineEdit.h"
 #include "Log.h"
 #include "Renderer.h"
@@ -39,9 +40,12 @@
 #include "DebugNew.h"
 
 static const int DEFAULT_CONSOLE_ROWS = 16;
+static const int DEFAULT_HISTORY_SIZE = 16;
 
 Console::Console(Engine* engine) :
-    mEngine(engine)
+    mEngine(engine),
+    mHistoryRows(DEFAULT_HISTORY_SIZE),
+    mHistoryPosition(0)
 {
     LOGINFO("Console created");
     
@@ -70,6 +74,7 @@ Console::Console(Engine* engine) :
         updateElements();
         
         subscribeToEvent(mLineEdit, EVENT_TEXTFINISHED, EVENT_HANDLER(Console, handleTextFinished));
+        subscribeToEvent(mLineEdit, EVENT_UNHANDLEDKEY, EVENT_HANDLER(Console, handleLineEditKey));
         subscribeToEvent(EVENT_WINDOWRESIZED, EVENT_HANDLER(Console, handleWindowResized));
         subscribeToEvent(EVENT_LOGMESSAGE, EVENT_HANDLER(Console, handleLogMessage));
     }
@@ -148,6 +153,15 @@ void Console::setNumRows(unsigned rows)
     updateElements();
 }
 
+void Console::setNumHistoryRows(unsigned rows)
+{
+    mHistoryRows = rows;
+    if (mHistory.size() > rows)
+        mHistory.resize(rows);
+    if (mHistoryPosition > rows)
+        mHistoryPosition = rows;
+}
+
 void Console::updateElements()
 {
     int width = mEngine->getRenderer()->getWidth();
@@ -162,15 +176,67 @@ bool Console::isVisible() const
     return mBackground->isVisible();
 }
 
+const std::string& Console::getHistoryRow(unsigned index) const
+{
+    static const std::string noRow;
+    return index < mHistory.size() ? mHistory[index] : noRow;
+}
+
 void Console::handleTextFinished(StringHash eventType, VariantMap& eventData)
 {
     using namespace TextFinished;
     
     std::string line = mLineEdit->getText();
-    ScriptEngine* scriptEngine = mEngine->getScriptEngine();
-    if (scriptEngine)
-        scriptEngine->execute(line);
-    mLineEdit->setText(std::string());
+    if (!line.empty())
+    {
+        ScriptEngine* scriptEngine = mEngine->getScriptEngine();
+        if (scriptEngine)
+            scriptEngine->execute(line);
+        
+        // Store to history, then clear the lineedit
+        mHistory.push_back(line);
+        if (mHistory.size() > mHistoryRows)
+            mHistory.erase(mHistory.begin());
+        mHistoryPosition = mHistory.size();
+        mLineEdit->setText(std::string());
+    }
+}
+
+void Console::handleLineEditKey(StringHash eventType, VariantMap& eventData)
+{
+    if (!mHistoryRows)
+        return;
+    
+    using namespace UnhandledKey;
+    
+    bool changed = false;
+    
+    switch(eventData[P_KEY].getInt())
+    {
+    case KEY_UP:
+        if (mHistoryPosition > 0)
+        {
+            --mHistoryPosition;
+            changed = true;
+        }
+        break;
+    
+    case KEY_DOWN:
+        if (mHistoryPosition < mHistory.size())
+        {
+            ++mHistoryPosition;
+            changed = true;
+        }
+        break;
+    }
+    
+    if (changed)
+    {
+        if (mHistoryPosition < mHistory.size())
+            mLineEdit->setText(mHistory[mHistoryPosition]);
+        else
+            mLineEdit->setText(std::string());
+    }
 }
 
 void Console::handleWindowResized(StringHash eventType, VariantMap& eventData)

+ 18 - 2
Engine/Engine/Console.h

@@ -49,8 +49,10 @@ public:
     void setVisible(bool enable);
     //! Toggle visibility
     void toggle();
-    //! Set number of rows
+    //! Set number of displayed rows
     void setNumRows(unsigned rows);
+    //! Set command history maximum size, 0 disables history
+    void setNumHistoryRows(unsigned rows);
     //! Update elements to layout properly. Call this after manually adjusting the sub-elements
     void updateElements();
     
@@ -62,12 +64,20 @@ public:
     LineEdit* getLineEdit() const { return mLineEdit; }
     //! Return whether is visible
     bool isVisible() const;
-    //! Return number of rows
+    //! Return number of displayed rows
     unsigned getNumRows() const { return mRows.size(); }
+    //! Return history maximum size
+    unsigned getNumHistoryRows() const { return mHistoryRows; }
+    //! Return current history position
+    unsigned getHistoryPosition() const { return mHistoryPosition; }
+    //! Return history row at index
+    const std::string& getHistoryRow(unsigned index) const;
     
 private:
     //! Handle enter pressed on the line edit
     void handleTextFinished(StringHash eventType, VariantMap& eventData);
+    //! Handle unhandled key on the line edit for scrolling the history
+    void handleLineEditKey(StringHash eventType, VariantMap& eventData);
     //! Handle rendering window resize
     void handleWindowResized(StringHash eventType, VariantMap& eventData);
     //! Handle a log message
@@ -83,6 +93,12 @@ private:
     std::vector<SharedPtr<Text> > mRows;
     //! Line edit
     SharedPtr<LineEdit> mLineEdit;
+    //! Command history
+    std::vector<std::string> mHistory;
+    //! Command history maximum rows
+    unsigned mHistoryRows;
+    //! Command history current position
+    unsigned mHistoryPosition;
 };
 
 #endif // ENGINE_CONSOLE_H

+ 7 - 0
Engine/Engine/EngineComponentFactory.cpp

@@ -38,8 +38,15 @@ Component* EngineComponentFactory::createComponent(ShortStringHash type, const s
 {
     if (type == AnimationController::getTypeStatic())
         return new AnimationController(name);
+    
     if (type == ParticleEmitter::getTypeStatic())
         return new ParticleEmitter(mOctree, name);
     
     return 0;
 }
+
+void EngineComponentFactory::getComponentTypes(std::vector<std::string>& dest)
+{
+    dest.push_back(AnimationController::getTypeNameStatic());
+    dest.push_back(ParticleEmitter::getTypeNameStatic());
+}

+ 2 - 0
Engine/Engine/EngineComponentFactory.h

@@ -38,6 +38,8 @@ public:
     
     //! Create a component of the specified type. Return null if can not create
     virtual Component* createComponent(ShortStringHash type, const std::string& name = std::string());
+    //! Return type names of components that can be created
+    virtual void getComponentTypes(std::vector<std::string>& dest);
     
 private:
     //! Octree

+ 2 - 2
Engine/Engine/RegisterCommon.cpp

@@ -476,8 +476,8 @@ static void registerVariant(asIScriptEngine* engine)
 
 static CScriptArray* Split(char separator, const std::string* str)
 {
-    std::vector<std::string> ret = split(*str, separator);
-    return vectorToArray<std::string>(ret, "array<string>");
+    std::vector<std::string> result = split(*str, separator);
+    return vectorToArray<std::string>(result, "array<string>");
 }
 
 static void registerStringUtils(asIScriptEngine* engine)

+ 4 - 1
Engine/Engine/RegisterEngine.cpp

@@ -370,13 +370,16 @@ static void registerConsole(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Console", "void setVisible(bool)", asMETHOD(Console, setVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod("Console", "void toggle()", asMETHOD(Console, toggle), asCALL_THISCALL);
     engine->RegisterObjectMethod("Console", "void setNumRows(uint)", asMETHOD(Console, setNumRows), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Console", "void setNumHistoryRows(uint)", asMETHOD(Console, setNumHistoryRows), asCALL_THISCALL);
     engine->RegisterObjectMethod("Console", "void updateElements()", asMETHOD(Console, updateElements), asCALL_THISCALL);
     engine->RegisterObjectMethod("Console", "XMLFile@+ getStyle() const", asMETHOD(Console, getStyle), asCALL_THISCALL);
     engine->RegisterObjectMethod("Console", "BorderImage@+ getBackground() const", asMETHOD(Console, getBackground), asCALL_THISCALL);
     engine->RegisterObjectMethod("Console", "LineEdit@+ getLineEdit() const", asMETHOD(Console, getLineEdit), asCALL_THISCALL);
     engine->RegisterObjectMethod("Console", "bool isVisible() const", asMETHOD(Console, isVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod("Console", "uint getNumRows() const", asMETHOD(Console, getNumRows), asCALL_THISCALL);
-    
+    engine->RegisterObjectMethod("Console", "uint getNumHistoryRows() const", asMETHOD(Console, getNumHistoryRows), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Console", "uint getHistoryPosition() const", asMETHOD(Console, getHistoryPosition), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Console", "const string& getHistoryRow(uint) const", asMETHOD(Console, getHistoryRow), asCALL_THISCALL);
     engine->RegisterGlobalFunction("Console@+ getConsole()", asFUNCTION(GetConsole), asCALL_CDECL);
     engine->RegisterGlobalFunction("Console@+ get_console()", asFUNCTION(GetConsole), asCALL_CDECL);
 }

+ 8 - 0
Engine/Engine/RegisterScene.cpp

@@ -358,6 +358,13 @@ static void SceneLoadAsyncXML(File* file, Scene* ptr)
     TRY_SAFE_RETHROW(ptr->loadAsyncXML(file));
 }
 
+static CScriptArray* SceneGetComponentTypes(Scene* ptr)
+{
+    std::vector<std::string> result;
+    ptr->getComponentTypes(result);
+    return vectorToArray(result, "array<string>");
+}
+
 static CScriptArray* SceneGetAllEntities(Scene* ptr)
 {
     const std::map<EntityID, SharedPtr<Entity> >& entities = ptr->getAllEntities();
@@ -441,6 +448,7 @@ static void registerScene(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Scene", "void setInterpolationSnapThreshold(float)", asMETHOD(Scene, setInterpolationSnapThreshold), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "const string& getName() const", asMETHOD(Scene, getName), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "uint8 getNetFlags() const", asMETHOD(Scene, getNetFlags), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Scene", "array<string>@ getComponentTypes() const", asFUNCTION(SceneGetComponentTypes), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Scene", "bool hasEntity(uint) const", asMETHODPR(Scene, hasEntity, (EntityID) const, bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "bool hasEntity(Entity@+) const", asMETHODPR(Scene, hasEntity, (Entity*) const, bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "bool hasEntity(const string& in) const", asMETHODPR(Scene, hasEntity, (const std::string&) const, bool), asCALL_THISCALL);

+ 1 - 4
Engine/Network/Network.cpp

@@ -276,10 +276,7 @@ void Network::stopClient()
 
 Peer* Network::getPeer(unsigned index) const
 {
-    if (index >= mPeers.size())
-        return 0;
-    
-    return mPeers[index];
+    return index < mPeers.size() ? mPeers[index] : (Peer*)0;
 }
 
 Peer* Network::getServerPeer() const

+ 6 - 0
Engine/Physics/PhysicsComponentFactory.cpp

@@ -44,3 +44,9 @@ Component* PhysicsComponentFactory::createComponent(ShortStringHash type, const
     
     return 0;
 }
+
+void PhysicsComponentFactory::getComponentTypes(std::vector<std::string>& dest)
+{
+    dest.push_back(RigidBody::getTypeNameStatic());
+    dest.push_back(Joint::getTypeNameStatic());
+}

+ 2 - 0
Engine/Physics/PhysicsComponentFactory.h

@@ -38,6 +38,8 @@ public:
     
     //! Create a component of the specified type. Return null if can not create
     virtual Component* createComponent(ShortStringHash type, const std::string& name = std::string());
+    //! Return type names of components that can be created
+    virtual void getComponentTypes(std::vector<std::string>& dest);
     
 private:
     //! Physics world

+ 2 - 7
Engine/Renderer/AnimatedModel.cpp

@@ -887,10 +887,7 @@ void AnimatedModel::syncMorphs(AnimatedModel* srcNode)
 
 float AnimatedModel::getMorphWeight(unsigned index) const
 {
-    if (index >= mMorphs.size())
-        return 0.0f;
-    
-    return mMorphs[index].mWeight;
+    return index < mMorphs.size() ? mMorphs[index].mWeight : 0.0f;
 }
 
 float AnimatedModel::getMorphWeight(const std::string& name) const
@@ -956,9 +953,7 @@ AnimationState* AnimatedModel::getAnimationState(StringHash animationNameHash) c
 
 AnimationState* AnimatedModel::getAnimationState(unsigned index) const
 {
-    if (index >= mAnimationStates.size())
-        return 0;
-    return mAnimationStates[index];
+    return index < mAnimationStates.size() ? mAnimationStates[index] : 0;
 }
 
 void AnimatedModel::setSkeleton(const Skeleton& skeleton)

+ 1 - 4
Engine/Renderer/Animation.cpp

@@ -149,10 +149,7 @@ unsigned Animation::getNumTracks() const
 
 const AnimationTrack* Animation::getTrack(unsigned index) const
 {
-    if (index >= mTracks.size())
-        return 0;
-    
-    return &mTracks[index];
+    return index < mTracks.size() ? &mTracks[index] : 0;
 }
 
 const AnimationTrack* Animation::getTrack(const std::string& name) const

+ 1 - 4
Engine/Renderer/BillboardSet.cpp

@@ -380,10 +380,7 @@ void BillboardSet::updated()
 
 Billboard* BillboardSet::getBillboard(unsigned index)
 {
-    if (index >= mBillboards.size())
-        return 0;
-    
-    return &mBillboards[index];
+    return index < mBillboards.size() ? &mBillboards[index] : (Billboard*)0;
 }
 
 void BillboardSet::onMarkedDirty()

+ 2 - 8
Engine/Renderer/CustomObject.cpp

@@ -481,18 +481,12 @@ void CustomObject::setOptimization(bool enable)
 
 const CustomGeometry* CustomObject::getGeometry(unsigned index) const
 {
-    if (index >= mCustomGeometries.size())
-        return 0;
-    
-    return &mCustomGeometries[index];
+    return index < mCustomGeometries.size() ? &mCustomGeometries[index] : (CustomGeometry*)0;
 }
 
 Material* CustomObject::getMaterial(unsigned index) const
 {
-    if (index >= mCustomGeometries.size())
-        return 0;
-    
-    return mCustomGeometries[index].mMaterial;
+    return index < mCustomGeometries.size() ? mCustomGeometries[index].mMaterial : (Material*)0;
 }
 
 void CustomObject::onWorldBoundingBoxUpdate(BoundingBox& worldBoundingBox)

+ 2 - 8
Engine/Renderer/Geometry.cpp

@@ -184,18 +184,12 @@ void Geometry::draw(Renderer* renderer)
 
 VertexBuffer* Geometry::getVertexBuffer(unsigned index) const
 {
-    if (index >= mVertexBuffers.size())
-        return 0;
-    
-    return mVertexBuffers[index];
+    return index < mVertexBuffers.size() ? mVertexBuffers[index] : (VertexBuffer*)0;
 }
 
 unsigned Geometry::getVertexElementMask(unsigned index) const
 {
-    if (index >= mVertexElementMasks.size())
-        return 0;
-    
-    return mVertexElementMasks[index];
+    return index < mVertexElementMasks.size() ? mVertexElementMasks[index] : 0;
 }
 
 unsigned short Geometry::getBufferHash() const

+ 2 - 8
Engine/Renderer/InstancedModel.cpp

@@ -620,18 +620,12 @@ void InstancedModel::updated()
 
 Material* InstancedModel::getMaterial(unsigned index) const
 {
-    if (index >= mOriginalMaterials.size())
-        return 0;
-    
-    return mOriginalMaterials[index];
+    return index < mOriginalMaterials.size() ? mOriginalMaterials[index] : (Material*)0;
 }
 
 Instance* InstancedModel::getInstance(unsigned index)
 {
-    if (index >= mInstances.size())
-        return 0;
-    
-    return &mInstances[index];
+    return index < mInstances.size() ? &mInstances[index] : (Instance*)0;
 }
 
 void InstancedModel::onMarkedDirty()

+ 1 - 4
Engine/Renderer/Material.cpp

@@ -675,10 +675,7 @@ SharedPtr<Material> Material::clone(const std::string& cloneName) const
 
 MaterialTechnique* Material::getTechnique(unsigned index)
 {
-    if (index >= mTechniques.size())
-        return 0;
-    
-    return &mTechniques[index];
+    return index < mTechniques.size() ? &mTechniques[index] : 0;
 }
 
 MaterialPass* Material::getPass(unsigned technique, PassType pass)

+ 2 - 6
Engine/Renderer/Model.cpp

@@ -400,9 +400,7 @@ void Model::setOcclusionLodLevel(unsigned lodLevel)
 
 unsigned Model::getNumGeometryLodLevels(unsigned index) const
 {
-    if (index >= mGeometries.size())
-        return 0;
-    return mGeometries[index].size();
+    return index < mGeometries.size() ? mGeometries[index].size() : 0;
 }
 
 Geometry* Model::getGeometry(unsigned index, unsigned lodLevel) const
@@ -415,9 +413,7 @@ Geometry* Model::getGeometry(unsigned index, unsigned lodLevel) const
 
 const ModelMorph* Model::getMorph(unsigned index) const
 {
-    if (index >= mMorphs.size())
-        return 0;
-    return &mMorphs[index];
+    return index < mMorphs.size() ? &mMorphs[index] : 0;
 }
 
 const ModelMorph* Model::getMorph(const std::string& name) const

+ 2 - 6
Engine/Renderer/Pipeline.cpp

@@ -441,12 +441,8 @@ void Pipeline::setDrawDebugGeometry(bool enable)
 
 const Viewport& Pipeline::getViewport(unsigned index) const
 {
-    static const Viewport emptyViewport;
-    
-    if (index >= mViewports.size())
-        return emptyViewport;
-    else
-        return mViewports[index];
+    static const Viewport noViewport;
+    return index < mViewports.size() ? mViewports[index] : noViewport;
 }
 
 VertexShader* Pipeline::getVertexShader(const std::string& name, bool checkExists) const

+ 4 - 16
Engine/Renderer/Renderer.cpp

@@ -1802,34 +1802,22 @@ std::vector<int> Renderer::getMultiSampleSupport() const
 
 VertexBuffer* Renderer::getVertexBuffer(unsigned index) const
 {
-    if (index >= MAX_VERTEX_STREAMS)
-        return 0;
-    
-    return mVertexBuffer[index];
+    return index < MAX_VERTEX_STREAMS ? mVertexBuffer[index] : 0;
 }
 
 Texture* Renderer::getTexture(unsigned index) const
 {
-    if (index >= MAX_TEXTURE_UNITS)
-        return 0;
-    
-    return mTexture[index];
+    return index < MAX_TEXTURE_UNITS ? mTexture[index] : 0;
 }
 
 RenderSurface* Renderer::getRenderTarget(unsigned index) const
 {
-    if (index >= MAX_RENDERTARGETS)
-        return 0;
-    
-    return mRenderTarget[index];
+    return index < MAX_RENDERTARGETS ? mRenderTarget[index] : 0;
 }
 
 unsigned Renderer::getStreamFrequency(unsigned index) const
 {
-    if (index >= MAX_VERTEX_STREAMS)
-        return 0;
-    
-    return mStreamFrequency[index];
+    return index < MAX_VERTEX_STREAMS ? mStreamFrequency[index] : 0;
 }
 
 IntVector2 Renderer::getRenderTargetDimensions() const

+ 14 - 0
Engine/Renderer/RendererComponentFactory.cpp

@@ -74,3 +74,17 @@ Component* RendererComponentFactory::createComponent(ShortStringHash type, const
     
     return 0;
 }
+
+void RendererComponentFactory::getComponentTypes(std::vector<std::string>& dest)
+{
+    dest.push_back(Camera::getTypeNameStatic());
+    dest.push_back(Bone::getTypeNameStatic());
+    dest.push_back(Light::getTypeNameStatic());
+    dest.push_back(StaticModel::getTypeNameStatic());
+    dest.push_back(AnimatedModel::getTypeNameStatic());
+    dest.push_back(InstancedModel::getTypeNameStatic());
+    dest.push_back(BillboardSet::getTypeNameStatic());
+    dest.push_back(CustomObject::getTypeNameStatic());
+    dest.push_back(Skybox::getTypeNameStatic());
+    dest.push_back(Zone::getTypeNameStatic());
+}

+ 2 - 0
Engine/Renderer/RendererComponentFactory.h

@@ -38,6 +38,8 @@ public:
     
     //! Create a component of the specified type. Return null if can not create
     virtual Component* createComponent(ShortStringHash type, const std::string& name = std::string());
+    //! Return type names of components that can be created
+    virtual void getComponentTypes(std::vector<std::string>& dest);
     
 private:
     //! Octree

+ 1 - 4
Engine/Renderer/Skeleton.cpp

@@ -198,10 +198,7 @@ void Skeleton::reset(bool force)
 
 Bone* Skeleton::getBone(unsigned index) const
 {
-    if (index >= mBones.size())
-        return 0;
-    
-    return mBones[index];
+    return index < mBones.size() ? mBones[index] : (Bone*)0;
 }
 
 Bone* Skeleton::getBone(const std::string& name) const

+ 1 - 4
Engine/Renderer/StaticModel.cpp

@@ -352,10 +352,7 @@ bool StaticModel::setMaterial(unsigned index, Material* material)
 
 Material* StaticModel::getMaterial(unsigned index) const
 {
-    if (index >= mMaterials.size())
-        return 0;
-    
-    return mMaterials[index];
+    return index < mMaterials.size() ? mMaterials[index] : (Material*)0;
 }
 
 void StaticModel::setBoundingBox(const BoundingBox& box)

+ 5 - 0
Engine/Scene/BaseComponentFactory.cpp

@@ -34,3 +34,8 @@ Component* BaseComponentFactory::createComponent(ShortStringHash type, const std
     
     return 0;
 }
+
+void BaseComponentFactory::getComponentTypes(std::vector<std::string>& dest)
+{
+    dest.push_back(Node::getTypeNameStatic());
+}

+ 2 - 0
Engine/Scene/BaseComponentFactory.h

@@ -32,6 +32,8 @@ class BaseComponentFactory : public ComponentFactory
 public:
     //! Create a component of the specified type. Return null if can not create
     virtual Component* createComponent(ShortStringHash type, const std::string& name = std::string());
+    //! Return type names of components that can be created
+    virtual void getComponentTypes(std::vector<std::string>& dest);
 };
 
 #endif // SCENE_BASECOMPONENTFACTORY_H

+ 2 - 0
Engine/Scene/ComponentFactory.h

@@ -35,6 +35,8 @@ class ComponentFactory : public RefCounted
 public:
     //! Create a component of the specified type. Return null if can not create
     virtual Component* createComponent(ShortStringHash type, const std::string& name = std::string()) = 0;
+    //! Return type names of components that can be created
+    virtual void getComponentTypes(std::vector<std::string>& dest) = 0;
 };
 
 #endif // SCENE_COMPONENTFACTORY

+ 1 - 4
Engine/Scene/Node.cpp

@@ -541,10 +541,7 @@ unsigned Node::getNumChildren(bool recursive) const
 
 Node* Node::getChild(unsigned index) const
 {
-    if (index >= mChildren.size())
-        return 0;
-    
-    return mChildren[index];
+    return index < mChildren.size() ? mChildren[index] : (Node*)0;
 }
 
 Node* Node::getChild(const std::string& name, bool recursive) const

+ 9 - 2
Engine/Scene/Scene.cpp

@@ -509,9 +509,9 @@ SharedPtr<Component> Scene::createComponent(ShortStringHash type, const std::str
 {
     SharedPtr<Component> component;
     
-    for (unsigned i = 0; i < mFactories.size(); ++i)
+    for (std::vector<SharedPtr<ComponentFactory> >::iterator i = mFactories.begin(); i != mFactories.end(); ++i)
     {
-        component = mFactories[i]->createComponent(type, name);
+        component = (*i)->createComponent(type, name);
         if (component)
         {
             // Set the authority flag to differentiate between singleplayer & server components
@@ -806,6 +806,13 @@ EntityID Scene::getNextLocalEntityID()
     return current;
 }
 
+void Scene::getComponentTypes(std::vector<std::string>& dest) const
+{
+    dest.clear();
+    for (std::vector<SharedPtr<ComponentFactory> >::const_iterator i = mFactories.begin(); i != mFactories.end(); ++i)
+        (*i)->getComponentTypes(dest);
+}
+
 bool Scene::hasEntity(EntityID id) const
 {
     return mEntities.find(id) != mEntities.end();

+ 2 - 0
Engine/Scene/Scene.h

@@ -146,6 +146,8 @@ public:
     const std::map<ShortStringHash, SharedPtr<SceneExtension> >& getExtensions() const { return mExtensions; }
     //! Return component factories
     const std::vector<SharedPtr<ComponentFactory> >& getComponentFactories() const { return mFactories; }
+    //! Return component types supported by the factories
+    void getComponentTypes(std::vector<std::string>& dest) const;
     //! Return whether has an entity by ID. This is preferred for performance
     bool hasEntity(EntityID id) const;
     //! Return whether has an entity by pointer. Needs to search through all entities

+ 5 - 0
Engine/Script/ScriptComponentFactory.cpp

@@ -40,3 +40,8 @@ Component* ScriptComponentFactory::createComponent(ShortStringHash type, const s
     
     return 0;
 }
+
+void ScriptComponentFactory::getComponentTypes(std::vector<std::string>& dest)
+{
+    dest.push_back(ScriptInstance::getTypeNameStatic());
+}

+ 2 - 0
Engine/Script/ScriptComponentFactory.h

@@ -38,6 +38,8 @@ public:
     
     //! Create a component of the specified type. Return null if can not create
     virtual Component* createComponent(ShortStringHash type, const std::string& name = std::string());
+    //! Return type names of components that can be created
+    virtual void getComponentTypes(std::vector<std::string>& dest);
     
 private:
     //! Script engine

+ 2 - 2
Engine/UI/FileSelector.cpp

@@ -112,7 +112,7 @@ FileSelector::FileSelector(UI* ui) :
     subscribeToEvent(mPathEdit, EVENT_TEXTFINISHED, EVENT_HANDLER(FileSelector, handlePathChanged));
     subscribeToEvent(mFileList, EVENT_ITEMSELECTED, EVENT_HANDLER(FileSelector, handleFileSelected));
     subscribeToEvent(mFileList, EVENT_ITEMDOUBLECLICKED, EVENT_HANDLER(FileSelector, handleFileDoubleClicked));
-    subscribeToEvent(mFileList, EVENT_LISTVIEWKEY, EVENT_HANDLER(FileSelector, handleFileListKey));
+    subscribeToEvent(mFileList, EVENT_UNHANDLEDKEY, EVENT_HANDLER(FileSelector, handleFileListKey));
     subscribeToEvent(mOKButton, EVENT_PRESSED, EVENT_HANDLER(FileSelector, handleOKPressed));
     subscribeToEvent(mCancelButton, EVENT_PRESSED, EVENT_HANDLER(FileSelector, handleCancelPressed));
 }
@@ -422,7 +422,7 @@ void FileSelector::handleFileListKey(StringHash eventType, VariantMap& eventData
     if (mIgnoreEvents)
         return;
     
-    using namespace ListViewKey;
+    using namespace UnhandledKey;
     
     if (eventData[P_KEY].getInt() == KEY_RETURN)
     {

+ 18 - 3
Engine/UI/LineEdit.cpp

@@ -306,6 +306,22 @@ void LineEdit::onKey(int key, int buttons, int qualifiers)
             changed = true;
         }
         break;
+        
+    case KEY_UP:
+    case KEY_DOWN:
+    case KEY_PAGEUP:
+    case KEY_PAGEDOWN:
+        {
+            using namespace UnhandledKey;
+            
+            VariantMap eventData;
+            eventData[P_ELEMENT] = (void*)this;
+            eventData[P_KEY] = key;
+            eventData[P_BUTTONS] = buttons;
+            eventData[P_QUALIFIERS] = qualifiers;
+            sendEvent(EVENT_UNHANDLEDKEY, eventData);
+        }
+        break;
     }
     
     if (changed)
@@ -414,10 +430,9 @@ void LineEdit::setText(const std::string& text)
     if (text != mLine)
     {
         mLine = text;
-        // If cursor is not movable, make sure it's at the text end
-        if (!mCursorMovable)
-            setCursorPosition(mLine.length());
+        mCursorPosition = mLine.length();
         updateText();
+        updateCursor();
     }
 }
 

+ 2 - 2
Engine/UI/ListView.cpp

@@ -226,14 +226,14 @@ void ListView::onKey(int key, int buttons, int qualifiers)
         }
     }
     
-    using namespace ListViewKey;
+    using namespace UnhandledKey;
     
     VariantMap eventData;
     eventData[P_ELEMENT] = (void*)this;
     eventData[P_KEY] = key;
     eventData[P_BUTTONS] = buttons;
     eventData[P_QUALIFIERS] = qualifiers;
-    sendEvent(EVENT_LISTVIEWKEY, eventData);
+    sendEvent(EVENT_UNHANDLEDKEY, eventData);
 }
 
 void ListView::onResize()

+ 1 - 4
Engine/UI/UIElement.cpp

@@ -879,10 +879,7 @@ unsigned UIElement::getNumChildren(bool recursive) const
 
 UIElement* UIElement::getChild(unsigned index) const
 {
-    if (index >= mChildren.size())
-        return 0;
-    
-    return mChildren[index];
+    return index < mChildren.size() ? mChildren[index] : (UIElement*)0;
 }
 
 UIElement* UIElement::getChild(const std::string& name, bool recursive) const

+ 2 - 2
Engine/UI/UIEvents.h

@@ -156,8 +156,8 @@ DEFINE_EVENT(EVENT_ITEMDOUBLECLICKED, ItemDoubleClicked)
     EVENT_PARAM(P_SELECTION, Selection);        // int
 }
 
-//! Listview unhandled key pressed
-DEFINE_EVENT(EVENT_LISTVIEWKEY, ListViewKey)
+//! LineEdit or Listview unhandled key pressed
+DEFINE_EVENT(EVENT_UNHANDLEDKEY, UnhandledKey)
 {
     EVENT_PARAM(P_ELEMENT, Element);            // UIElement pointer
     EVENT_PARAM(P_KEY, Key);                    // int

+ 9 - 0
Examples/NinjaSnowWar/GameObjectFactory.cpp

@@ -50,3 +50,12 @@ Component* GameObjectFactory::createComponent(ShortStringHash type, const std::s
     
     return 0;
 }
+
+void GameObjectFactory::getComponentTypes(std::vector<std::string>& dest)
+{
+    dest.push_back(GameObject::getTypeNameStatic());
+    dest.push_back(Ninja::getTypeNameStatic());
+    dest.push_back(SnowBall::getTypeNameStatic());
+    dest.push_back(SnowCrate::getTypeNameStatic());
+    dest.push_back(Potion::getTypeNameStatic());
+}

+ 1 - 0
Examples/NinjaSnowWar/GameObjectFactory.h

@@ -29,6 +29,7 @@
 class GameObjectFactory : public ComponentFactory
 {
     virtual Component* createComponent(ShortStringHash type, const std::string& name = std::string());
+    virtual void getComponentTypes(std::vector<std::string>& dest);
 };
 
 #endif // GAMEOBJECTFACTORY_H