Browse Source

Initial file menu in the editor.
Added getFilterIndex() to FileSelector.
Popup menus hide themselves when another unrelated element focused.

Lasse Öörni 15 years ago
parent
commit
5c98ad85df

+ 3 - 0
Bin/CoreData/Scripts/EditorScene.as

@@ -1,6 +1,7 @@
 // Urho3D editor scene handling
 
 Scene@ editorScene;
+string sceneFileName;
 string sceneResourcePath;
 
 void createScene()
@@ -44,4 +45,6 @@ void loadScene(string fileName)
         editorScene.loadXML(file);
     else
         editorScene.load(file);
+        
+    sceneFileName = fileName;
 }

+ 104 - 5
Bin/CoreData/Scripts/EditorUI.as

@@ -2,16 +2,23 @@
 
 const int uiSpacing = 2;
 const IntRect uiSpacingRect(uiSpacing, uiSpacing, uiSpacing, uiSpacing);
+
+XMLFile@ uiStyle;
 UIElement@ uiMenuBar;
+FileSelector@ uiFileSelector;
+
+array<string> uiSceneFilters = {"*.xml", "*.scn", "*.*"};
+uint uiSceneFilter = 0;
 
 void createUI()
 {
-    XMLFile@ uiStyle = cache.getResource("XMLFile", "UI/DefaultStyle.xml");
+    @uiStyle = cache.getResource("XMLFile", "UI/DefaultStyle.xml");
 
     createCursor(uiStyle);
     createMenuBar(uiStyle);
     
     subscribeToEvent("ScreenMode", "handleScreenMode");
+    subscribeToEvent("MenuSelected", "handleMenuSelected");
 }
 
 void createCursor(XMLFile@ uiStyle)
@@ -29,35 +36,127 @@ void createMenuBar(XMLFile@ uiStyle)
     uiMenuBar.setLayout(LM_HORIZONTAL, uiSpacing, uiSpacingRect);
     uiRoot.addChild(uiMenuBar);
 
-    Menu@ fileMenu = createMenu(uiStyle, "File");
-    uiMenuBar.addChild(fileMenu);
+    {
+        Menu@ fileMenu = createMenu(uiStyle, "File");
+        Window@ filePopup = fileMenu.getPopup();
+        filePopup.addChild(createMenuItem(uiStyle, "Load scene"));
+        filePopup.addChild(createMenuItem(uiStyle, "Save scene"));
+        filePopup.addChild(createMenuItem(uiStyle, "Save scene as"));
+        filePopup.addChild(createMenuSpacer(uiStyle));
+        filePopup.addChild(createMenuItem(uiStyle, "Exit"));
+        uiMenuBar.addChild(fileMenu);
+    }
+
     UIElement@ spacer = UIElement("MenuBarSpacer");
     uiMenuBar.addChild(spacer);
 
     resizeUI();
 }
 
-Menu@ createMenu(XMLFile@ uiStyle, string title)
+Menu@ createMenuItem(XMLFile@ uiStyle, string title)
 {
     Menu@ menu = Menu(title);
     menu.setStyleAuto(uiStyle);
     menu.setLayout(LM_HORIZONTAL, 0, IntRect(uiSpacing, 0, uiSpacing, 0));
 
-    Text@ menuText = Text(title + "Text");
+    Text@ menuText = Text(title + "_Text");
     menuText.setStyle(uiStyle, "EditorMenuText");
     menuText.setText(title);
     menu.addChild(menuText);
+
+    return menu;
+}
+
+Menu@ createMenuSpacer(XMLFile@ uiStyle)
+{
+    Menu@ spacer = Menu("");
+    spacer.setStyleAuto(uiStyle);
+    spacer.setFixedHeight(2);
+    // Disable input, but set permanent selection to get a nice indentation effect
+    spacer.setEnabled(false);
+    spacer.setSelected(true);
+
+    return spacer;
+}
+
+Window@ createPopup(XMLFile@ uiStyle, Menu@ baseMenu)
+{
+    Window@ popup = Window(baseMenu.getName() + "_Popup");
+    popup.setStyleAuto(uiStyle);
+    popup.setLayout(LM_VERTICAL, uiSpacing, uiSpacingRect);
+    baseMenu.setPopup(popup);
+    baseMenu.setPopupOffset(0, baseMenu.getHeight());
+
+    return popup;
+}
+
+Menu@ createMenu(XMLFile@ uiStyle, string title)
+{
+    Menu@ menu = createMenuItem(uiStyle, title);
     menu.setFixedWidth(menu.getWidth());
+    createPopup(uiStyle, menu);
 
     return menu;
 }
 
+void createFileSelector(string title, string ok, string cancel, string initialPath, array<string>@ filters,
+    uint initialFilter)
+{
+    // Within the editor UI, the file selector is a kind of a "singleton". When the previous one is overwritten, also 
+    // the events subscribed from it are disconnected, so new ones are safe to subscribe.
+    @uiFileSelector = FileSelector();
+    uiFileSelector.setStyle(uiStyle);
+    uiFileSelector.setTitle(title);
+    uiFileSelector.setButtonTexts(ok, cancel);
+    uiFileSelector.setPath(initialPath);
+    uiFileSelector.setFilters(filters, initialFilter);
+    
+    Window@ window = uiFileSelector.getWindow();
+    IntVector2 size = window.getSize();
+    window.setPosition((renderer.getWidth() - size.x) / 2, (renderer.getHeight() - size.y) / 2);
+}
+
+void closeFileSelector()
+{
+    @uiFileSelector = null;
+}
+
 void resizeUI()
 {
     uiMenuBar.setFixedWidth(renderer.getWidth());
 }
 
+void handleMenuSelected(StringHash eventType, VariantMap& eventData)
+{
+    Menu@ menu = eventData["Element"].getUIElement();
+    if (menu is null)
+        return;
+
+    if ((menu.getName() == "Load scene") && (uiFileSelector is null))
+    {
+        createFileSelector("Load scene", "Load", "Cancel", getPath(sceneFileName), uiSceneFilters, uiSceneFilter);
+        subscribeToEvent(uiFileSelector, "FileSelected", "handleLoadSceneFile");
+    }
+
+    if (menu.getName() == "Exit")
+        engine.exit();
+}
+
 void handleScreenMode(StringHash eventType, VariantMap& eventData)
 {
     resizeUI();
 }
+
+void handleLoadSceneFile(StringHash eventType, VariantMap& eventData)
+{
+    // Save filter for next time
+    uiSceneFilter = uiFileSelector.getFilterIndex();
+    closeFileSelector();
+
+    // Check for cancel
+    if (!eventData["OK"].getBool())
+        return;
+
+    string fileName = eventData["FileName"].getString();
+    loadScene(fileName);
+}

+ 1 - 1
Bin/CoreData/UI/DefaultStyle.xml

@@ -377,6 +377,6 @@
         <border value="2 2 2 2" />
     </element>
     <element type="EditorMenuText">
-        <font name="cour.ttf" size="12" />
+        <font name="cour.ttf" size="10" />
     </element>
 </elements>

+ 1 - 0
Engine/Engine/RegisterUI.cpp

@@ -419,6 +419,7 @@ static void registerFileSelector(asIScriptEngine* engine)
     engine->RegisterObjectMethod("FileSelector", "const string& getPath() const", asMETHOD(FileSelector, getPath), asCALL_THISCALL);
     engine->RegisterObjectMethod("FileSelector", "const string& getFileName() const", asMETHOD(FileSelector, getFileName), asCALL_THISCALL);
     engine->RegisterObjectMethod("FileSelector", "const string& getFilter() const", asMETHOD(FileSelector, getFilter), asCALL_THISCALL);
+    engine->RegisterObjectMethod("FileSelector", "uint getFilterIndex() const", asMETHOD(FileSelector, getFilterIndex), asCALL_THISCALL);
     registerRefCasts<EventListener, FileSelector>(engine, "EventListener", "FileSelector");
 }
 

+ 14 - 2
Engine/UI/FileSelector.cpp

@@ -101,13 +101,16 @@ FileSelector::FileSelector(UI* ui) :
     mWindow->addChild(mButtonLayout);
     
     mUI->getRootElement()->addChild(mWindow);
-    mWindow->bringToFront();
     
     std::vector<std::string> defaultFilters;
     defaultFilters.push_back("*.*");
     setFilters(defaultFilters, 0);
     setPath(getCurrentDirectory());
     
+    // Focus the fileselector's filelist initially when created, and bring to front
+    mUI->setFocusElement(mFileList);
+    mWindow->bringToFront();
+    
     subscribeToEvent(mFilterList, EVENT_ITEMSELECTED, EVENT_HANDLER(FileSelector, handleFilterChanged));
     subscribeToEvent(mPathEdit, EVENT_TEXTFINISHED, EVENT_HANDLER(FileSelector, handlePathChanged));
     subscribeToEvent(mFileList, EVENT_ITEMSELECTED, EVENT_HANDLER(FileSelector, handleFileSelected));
@@ -219,6 +222,8 @@ void FileSelector::setFilters(const std::vector<std::string>& filters, unsigned
         filterText->setStyle(mStyle, "FileSelectorFilterText", mUI->getResourceCache());
         mFilterList->addItem(filterText);
     }
+    if (defaultIndex > filters.size())
+        defaultIndex = 0;
     mFilterList->setSelection(defaultIndex);
     mIgnoreEvents = false;
     if (getFilter() != mLastUsedFilter)
@@ -259,6 +264,11 @@ const std::string& FileSelector::getFilter() const
     return emptyFilter;
 }
 
+unsigned FileSelector::getFilterIndex() const
+{
+    return mFilterList->getSelection();
+}
+
 void FileSelector::refreshFiles()
 {
     mIgnoreEvents = true;
@@ -332,6 +342,8 @@ bool FileSelector::enterFile()
             std::string parentPath = getParentPath(mPath);
             setPath(parentPath);
         }
+        
+        return true;
     }
     else
     {
@@ -344,7 +356,7 @@ bool FileSelector::enterFile()
         sendEvent(EVENT_FILESELECTED, eventData);
     }
     
-    return true;
+    return false;
 }
 
 void FileSelector::handleFilterChanged(StringHash eventType, VariantMap& eventData)

+ 3 - 1
Engine/UI/FileSelector.h

@@ -93,11 +93,13 @@ public:
     const std::string& getFileName() const;
     //! Return current filter
     const std::string& getFilter() const;
+    //! Return current filter index
+    unsigned getFilterIndex() const;
     
 private:
     //! Refresh the directory listing
     void refreshFiles();
-    //! Enter a directory or confirm a file. Return true if selection valid
+    //! Enter a directory or confirm a file. Return true if a directory entered
     bool enterFile();
     //! Handle filter changed
     void handleFilterChanged(StringHash eventType, VariantMap& eventData);

+ 3 - 2
Engine/UI/Menu.cpp

@@ -35,7 +35,8 @@ Menu::Menu(const std::string& name) :
     mPopupOffset(IntVector2::sZero),
     mShowPopup(false)
 {
-    subscribeToEvent(EVENT_UIMOUSECLICK, EVENT_HANDLER(Menu, handleUIMouseClick));
+    subscribeToEvent(EVENT_UIMOUSECLICK, EVENT_HANDLER(Menu, handleFocusChange));
+    subscribeToEvent(EVENT_FOCUSED, EVENT_HANDLER(Menu, handleFocusChange));
 }
 
 Menu::~Menu()
@@ -144,7 +145,7 @@ void Menu::showPopup(bool enable)
     mSelected = enable;
 }
 
-void Menu::handleUIMouseClick(StringHash eventType, VariantMap& eventData)
+void Menu::handleFocusChange(StringHash eventType, VariantMap& eventData)
 {
     if (!mShowPopup)
         return;

+ 2 - 2
Engine/UI/Menu.h

@@ -71,8 +71,8 @@ protected:
     bool mShowPopup;
     
 private:
-    //! Handle global UI mouseclick to check for hiding the popup
-    void handleUIMouseClick(StringHash eventType, VariantMap& eventData);
+    //! Handle global UI mouseclick or focus change to check for hiding the popup
+    void handleFocusChange(StringHash eventType, VariantMap& eventData);
 };
 
 #endif // UI_MENU_H