瀏覽代碼

Minor style edits. Use position instead of iterator in autocomplete to be safe against iterator invalidation. Add Lua binding to autocomplete. Add short description of the new feature being demonstrated in sample 26.

Lasse Öörni 9 年之前
父節點
當前提交
11f099c655

+ 1 - 0
Source/Samples/26_ConsoleInput/ConsoleInput.h

@@ -28,6 +28,7 @@
 /// This sample demonstrates:
 ///     - Implementing a crude text adventure game, which accepts input both through the engine console,
 ///       and standard input.
+///     - Adding autocomplete options to the engine console.
 class ConsoleInput : public Sample
 {
     URHO3D_OBJECT(ConsoleInput, Sample);

+ 56 - 57
Source/Urho3D/Engine/Console.cpp

@@ -42,9 +42,6 @@
 
 #include "../DebugNew.h"
 
-#include <algorithm>
-#include <vector>
-
 namespace Urho3D
 {
 
@@ -56,7 +53,8 @@ Console::Console(Context* context) :
     autoVisibleOnError_(false),
     historyRows_(DEFAULT_HISTORY_SIZE),
     historyPosition_(0),
-    historyOrAutoCompleteChange(false),
+    autoCompletePosition_(0),
+    historyOrAutoCompleteChange_(false),
     printing_(false)
 {
     UI* ui = GetSubsystem<UI>();
@@ -241,6 +239,25 @@ void Console::SetFocusOnShow(bool enable)
     focusOnShow_ = enable;
 }
 
+void Console::AddAutoComplete(const String& option)
+{
+    // Sorted insertion
+    Vector<String>::Iterator iter = UpperBound(autoComplete_.Begin(), autoComplete_.End(), option);
+    if (!iter.ptr_)
+        autoComplete_.Push(option);
+    // Make sure it isn't a duplicate
+    else if (iter == autoComplete_.Begin() || *(iter - 1) != option)
+        autoComplete_.Insert(iter, option);
+}
+
+void Console::RemoveAutoComplete(const String& option)
+{
+    // Erase and keep ordered
+    autoComplete_.Erase(LowerBound(autoComplete_.Begin(), autoComplete_.End(), option));
+    if (autoCompletePosition_ > autoComplete_.Size())
+        autoCompletePosition_ = autoComplete_.Size();
+}
+
 void Console::UpdateElements()
 {
     int width = GetSubsystem<UI>()->GetRoot()->GetWidth();
@@ -279,23 +296,6 @@ const String& Console::GetHistoryRow(unsigned index) const
     return index < history_.Size() ? history_[index] : String::EMPTY;
 }
 
-void Console::AddAutoComplete(const String & option)
-{
-    // sorted insertion
-    Vector<String>::Iterator iter = UpperBound(autoComplete_.Begin(), autoComplete_.End(), option);
-    if(!iter.ptr_)
-        autoComplete_.Push(option);
-    // make sure it isn't a duplicate
-    else if(iter == autoComplete_.Begin() || *(iter-1) != option)
-        autoComplete_.Insert(iter, option);
-}
-
-void Console::RemoveAutoComplete(const String & option)
-{
-    // erase and keep ordered
-    autoComplete_.Erase(LowerBound(autoComplete_.Begin(), autoComplete_.End(), option));
-}
-
 bool Console::PopulateInterpreter()
 {
     interpreters_->RemoveAllItems();
@@ -351,10 +351,10 @@ void Console::HandleTextChanged(StringHash eventType, VariantMap & eventData)
 {
     // Save the original line
     // Make sure the change isn't caused by auto complete or history
-    if (!historyOrAutoCompleteChange)
+    if (!historyOrAutoCompleteChange_)
         autoCompleteLine_ = eventData[TextEntry::P_TEXT].GetString();
 
-    historyOrAutoCompleteChange = false;
+    historyOrAutoCompleteChange_ = false;
 }
 
 void Console::HandleTextFinished(StringHash eventType, VariantMap& eventData)
@@ -385,9 +385,8 @@ void Console::HandleTextFinished(StringHash eventType, VariantMap& eventData)
                 history_.Erase(history_.Begin());
         }
 
-        historyPosition_ = history_.Size(); // reset
-
-        autoCompleteIter_ = autoComplete_.End(); // reset
+        historyPosition_ = history_.Size(); // Reset
+        autoCompletePosition_ = autoComplete_.Size(); // Reset
 
         currentRow_.Clear();
         lineEdit_->SetText(currentRow_);
@@ -406,37 +405,35 @@ void Console::HandleLineEditKey(StringHash eventType, VariantMap& eventData)
     switch (eventData[P_KEY].GetInt())
     {
     case KEY_UP:
-        if (autoCompleteIter_ == autoComplete_.Begin())
-            autoCompleteIter_ = autoComplete_.End();
+        if (autoCompletePosition_ == 0)
+            autoCompletePosition_ = autoComplete_.Size();
 
-        if (autoCompleteIter_ != autoComplete_.End())
+        if (autoCompletePosition_ < autoComplete_.Size())
         {
-            Vector<String>::Iterator before_begin = --autoComplete_.Begin();
-
             // Search for auto completion that contains the contents of the line
-            for (--autoCompleteIter_; autoCompleteIter_ != before_begin; --autoCompleteIter_)
+            for (--autoCompletePosition_; autoCompletePosition_ != M_MAX_UNSIGNED; --autoCompletePosition_)
             {
-                if (autoCompleteIter_->StartsWith(autoCompleteLine_))
+                const String& current = autoComplete_[autoCompletePosition_];
+                if (current.StartsWith(autoCompleteLine_))
                 {
-                    historyOrAutoCompleteChange = true;
-                    lineEdit_->SetText(*autoCompleteIter_);
+                    historyOrAutoCompleteChange_ = true;
+                    lineEdit_->SetText(current);
                     break;
                 }
             }
 
             // If not found
-            if (autoCompleteIter_ == before_begin)
+            if (autoCompletePosition_ == M_MAX_UNSIGNED)
             {
-                // Reset the iterator
-                autoCompleteIter_ = autoComplete_.End();
+                // Reset the position
+                autoCompletePosition_ = autoComplete_.Size();
                 // Reset history position
                 historyPosition_ = history_.Size();
             }
         }
         
         // If no more auto complete options and history options left
-        if (autoCompleteIter_ == autoComplete_.End() &&
-            historyPosition_ > 0)
+        if (autoCompletePosition_ == autoComplete_.Size() && historyPosition_ > 0)
         {
             // If line text is not a history, save the current text value to be restored later
             if (historyPosition_ == history_.Size())
@@ -458,33 +455,35 @@ void Console::HandleLineEditKey(StringHash eventType, VariantMap& eventData)
         else
         {
             // Loop over
-            if (autoCompleteIter_ == autoComplete_.End() || !autoCompleteIter_.ptr_)
-                autoCompleteIter_ = autoComplete_.Begin();
+            if (autoCompletePosition_ >= autoComplete_.Size())
+                autoCompletePosition_ = 0;
             else
-                ++autoCompleteIter_; // If not starting over, skip checking the currently found completion
+                ++autoCompletePosition_; // If not starting over, skip checking the currently found completion
 
-            Vector<String>::Iterator start_iter = autoCompleteIter_;
+            unsigned startPosition = autoCompletePosition_;
 
             // Search for auto completion that contains the contents of the line
-            for (; autoCompleteIter_ != autoComplete_.End(); ++autoCompleteIter_)
+            for (; autoCompletePosition_ < autoComplete_.Size(); ++autoCompletePosition_)
             {
-                if (autoCompleteIter_->StartsWith(autoCompleteLine_))
+                const String& current = autoComplete_[autoCompletePosition_];
+                if (current.StartsWith(autoCompleteLine_))
                 {
-                    historyOrAutoCompleteChange = true;
-                    lineEdit_->SetText(*autoCompleteIter_);
+                    historyOrAutoCompleteChange_ = true;
+                    lineEdit_->SetText(current);
                     break;
                 }
             }
 
             // Continue to search the complete range
-            if (autoCompleteIter_ == autoComplete_.End())
+            if (autoCompletePosition_ == autoComplete_.Size())
             {
-                for (autoCompleteIter_ = autoComplete_.Begin(); autoCompleteIter_ != start_iter; ++autoCompleteIter_)
+                for (autoCompletePosition_ = 0; autoCompletePosition_ != startPosition; ++autoCompletePosition_)
                 {
-                    if (autoCompleteIter_->StartsWith(autoCompleteLine_))
+                    const String& current = autoComplete_[autoCompletePosition_];
+                    if (current.StartsWith(autoCompleteLine_))
                     {
-                        historyOrAutoCompleteChange = true;
-                        lineEdit_->SetText(*autoCompleteIter_);
+                        historyOrAutoCompleteChange_ = true;
+                        lineEdit_->SetText(current);
                         break;
                     }
                 }
@@ -497,16 +496,16 @@ void Console::HandleLineEditKey(StringHash eventType, VariantMap& eventData)
 
     if (changed)
     {
-        historyOrAutoCompleteChange = true;
+        historyOrAutoCompleteChange_ = true;
         // Set text to history option
         if (historyPosition_ < history_.Size())
             lineEdit_->SetText(history_[historyPosition_]);
         else // restore the original line value before it was set to history values
         {
             lineEdit_->SetText(currentRow_);
-            // Set the auto complete iterator according to the currentRow
-            for (autoCompleteIter_ = autoComplete_.Begin(); autoCompleteIter_ != autoComplete_.End(); ++autoCompleteIter_)
-                if (autoCompleteIter_->StartsWith(currentRow_))
+            // Set the auto complete position according to the currentRow
+            for (autoCompletePosition_ = 0; autoCompletePosition_ < autoComplete_.Size(); ++autoCompletePosition_)
+                if (autoComplete_[autoCompletePosition_].StartsWith(currentRow_))
                     break;
         }
     }

+ 7 - 9
Source/Urho3D/Engine/Console.h

@@ -70,6 +70,10 @@ public:
     void SetNumHistoryRows(unsigned rows);
     /// Set whether to automatically focus the line edit when showing. Default true on desktops and false on mobile devices, as on mobiles it would pop up the screen keyboard.
     void SetFocusOnShow(bool enable);
+    /// Add auto complete option.
+    void AddAutoComplete(const String& option);
+    /// Remove auto complete option.
+    void RemoveAutoComplete(const String& option);
     /// Update elements to layout properly. Call this after manually adjusting the sub-elements.
     void UpdateElements();
 
@@ -112,12 +116,6 @@ public:
     /// Return history row at index.
     const String& GetHistoryRow(unsigned index) const;
 
-    /// Add auto complete option
-    void AddAutoComplete(const String& option);
-
-    /// Remove auto complete option
-    void RemoveAutoComplete(const String& option);
-
     /// Return whether automatically focuses the line edit when showing.
     bool GetFocusOnShow() const { return focusOnShow_; }
 
@@ -171,8 +169,6 @@ private:
     /// Command history current position.
     unsigned historyPosition_;
 
-    bool historyOrAutoCompleteChange;
-
     /**
     Command auto complete options.
 
@@ -185,7 +181,7 @@ private:
     */
     Vector<String> autoComplete_;
     /// Command auto complete current position.
-    Vector<String>::Iterator autoCompleteIter_;
+    unsigned autoCompletePosition_;
     /// Store the original line which is being auto-completed
     String autoCompleteLine_;
 
@@ -193,6 +189,8 @@ private:
     bool printing_;
     /// Flag for automatically focusing the line edit on showing the console.
     bool focusOnShow_;
+    /// Internal flag whether currently in an autocomplete or history change.
+    bool historyOrAutoCompleteChange_;
 };
 
 }

+ 2 - 0
Source/Urho3D/LuaScript/pkgs/Engine/Console.pkg

@@ -11,6 +11,8 @@ class Console : public Object
     void SetNumRows(unsigned rows);
     void SetNumHistoryRows(unsigned rows);
     void SetFocusOnShow(bool enable);
+    void AddAutoComplete(const String option);
+    void RemoveAutoComplete(const String option);
     void UpdateElements();
     
     XMLFile* GetDefaultStyle() const;

+ 7 - 0
bin/Data/LuaScripts/26_ConsoleInput.lua

@@ -3,6 +3,7 @@
 --     - Implementing a crude text adventure game, which accepts input both through the engine console,
 --       and standard input.
 --     - Disabling default execution of console commands as immediate mode Lua script.
+--     - Adding autocomplete options to the engine console.
 
 require "LuaScripts/Utilities/Sample"
 
@@ -53,6 +54,12 @@ function Start()
     console.commandInterpreter = "LuaScriptEventInvoker"
     console.visible = true
     console.closeButton.visible = false
+    console:AddAutoComplete("help")
+    console:AddAutoComplete("eat")
+    console:AddAutoComplete("hide")
+    console:AddAutoComplete("wait")
+    console:AddAutoComplete("score")
+    console:AddAutoComplete("quit")
 
     -- Show OS mouse cursor
     input.mouseVisible = true

+ 1 - 0
bin/Data/Scripts/26_ConsoleInput.as

@@ -3,6 +3,7 @@
 //     - Implementing a crude text adventure game, which accepts input both through the engine console,
 //       and standard input.
 //     - Disabling default execution of console commands as immediate mode AngelScript.
+//     - Adding autocomplete options to the engine console.
 
 #include "Scripts/Utilities/Sample.as"