From 818b617972eea37893747922e182d0575d798b8e Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 4 Jul 2016 16:01:49 -0500 Subject: [PATCH 1/3] Implements the right-mouse popup menus in the editor in SDL to make it match to Windows. --- Engine/source/gui/editor/guiPopupMenuCtrl.cpp | 184 ++++++++++++++++++ Engine/source/gui/editor/guiPopupMenuCtrl.h | 85 ++++++++ .../menus/guiPlatformGenericMenuBar.h | 29 +++ .../source/platformSDL/menus/menuBarSDL.cpp | 26 +-- .../source/platformSDL/menus/popupMenuSDL.cpp | 144 +++++++++++++- 5 files changed, 442 insertions(+), 26 deletions(-) create mode 100644 Engine/source/gui/editor/guiPopupMenuCtrl.cpp create mode 100644 Engine/source/gui/editor/guiPopupMenuCtrl.h create mode 100644 Engine/source/platformSDL/menus/guiPlatformGenericMenuBar.h diff --git a/Engine/source/gui/editor/guiPopupMenuCtrl.cpp b/Engine/source/gui/editor/guiPopupMenuCtrl.cpp new file mode 100644 index 000000000..36e693203 --- /dev/null +++ b/Engine/source/gui/editor/guiPopupMenuCtrl.cpp @@ -0,0 +1,184 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "gui/editor/guiPopupMenuCtrl.h" +#include "gfx/gfxDrawUtil.h" +#include "gfx/primBuilder.h" +#include "gui/core/guiCanvas.h" + +GuiPopupMenuBackgroundCtrl::GuiPopupMenuBackgroundCtrl(GuiPopupMenuTextListCtrl *textList) +{ + mTextList = textList; + mTextList->mBackground = this; +} + +void GuiPopupMenuBackgroundCtrl::onMouseDown(const GuiEvent &event) +{ + mTextList->setSelectedCell(Point2I(-1, -1)); + close(); +} + +void GuiPopupMenuBackgroundCtrl::onMouseMove(const GuiEvent &event) +{ +} + +void GuiPopupMenuBackgroundCtrl::onMouseDragged(const GuiEvent &event) +{ +} + +void GuiPopupMenuBackgroundCtrl::close() +{ + getRoot()->removeObject(this); +} + +GuiPopupMenuTextListCtrl::GuiPopupMenuTextListCtrl() +{ + isSubMenu = false; // Added + mMenu = NULL; + mMenuBar = NULL; + mPopup = NULL; +} + +void GuiPopupMenuTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver) +{ + if (dStrcmp(mList[cell.y].text + 3, "-\t")) // Was: dStrcmp(mList[cell.y].text + 2, "-\t")) but has been changed to take into account the submenu flag + Parent::onRenderCell(offset, cell, selected, mouseOver); + else + { + S32 yp = offset.y + mCellSize.y / 2; + GFX->getDrawUtil()->drawLine(offset.x, yp, offset.x + mCellSize.x, yp, ColorI(128, 128, 128)); + GFX->getDrawUtil()->drawLine(offset.x, yp + 1, offset.x + mCellSize.x, yp + 1, ColorI(255, 255, 255)); + } + // now see if there's a bitmap... + U8 idx = mList[cell.y].text[0]; + if (idx != 1) + { + // there's a bitmap... + U32 index = U32(idx - 2) * 3; + if (!mList[cell.y].active) + index += 2; + else if (selected || mouseOver) + index++; + + if (mProfile->mBitmapArrayRects.size() > index) + { + RectI rect = mProfile->mBitmapArrayRects[index]; + Point2I off = maxBitmapSize - rect.extent; + off /= 2; + + GFX->getDrawUtil()->clearBitmapModulation(); + GFX->getDrawUtil()->drawBitmapSR(mProfile->mTextureObject, offset + off, rect); + } + } + + // Check if this is a submenu + idx = mList[cell.y].text[1]; + if (idx != 1) + { + // This is a submenu, so draw an arrow + S32 left = offset.x + mCellSize.x - 12; + S32 right = left + 8; + S32 top = mCellSize.y / 2 + offset.y - 4; + S32 bottom = top + 8; + S32 middle = top + 4; + + PrimBuild::begin(GFXTriangleList, 3); + if (selected || mouseOver) + PrimBuild::color(mProfile->mFontColorHL); + else + PrimBuild::color(mProfile->mFontColor); + + PrimBuild::vertex2i(left, top); + PrimBuild::vertex2i(right, middle); + PrimBuild::vertex2i(left, bottom); + PrimBuild::end(); + } +} + +bool GuiPopupMenuTextListCtrl::onKeyDown(const GuiEvent &event) +{ + //if the control is a dead end, don't process the input: + if (!mVisible || !mActive || !mAwake) + return false; + + //see if the key down is a or not + if (event.modifier == 0) + { + if (event.keyCode == KEY_RETURN) + { + mBackground->close(); + return true; + } + else if (event.keyCode == KEY_ESCAPE) + { + mSelectedCell.set(-1, -1); + mBackground->close(); + return true; + } + } + + //otherwise, pass the event to it's parent + return Parent::onKeyDown(event); +} + +void GuiPopupMenuTextListCtrl::onMouseDown(const GuiEvent &event) +{ + Parent::onMouseDown(event); +} + +void GuiPopupMenuTextListCtrl::onMouseUp(const GuiEvent &event) +{ + Parent::onMouseUp(event); + + S32 selectionIndex = getSelectedCell().y; + + if (selectionIndex != -1) + { + GuiMenuBar::MenuItem *list = mMenu->firstMenuItem; + + while (selectionIndex && list) + { + list = list->nextMenuItem; + selectionIndex--; + } + if (list) + { + if (list->enabled) + dAtob(Con::executef(mPopup, "onSelectItem", Con::getIntArg(getSelectedCell().y), list->text ? list->text : "")); + } + } + + mSelectedCell.set(-1, -1); + mBackground->close(); +} + +void GuiPopupMenuTextListCtrl::onCellHighlighted(Point2I cell) +{ + // If this text list control is part of a submenu, then don't worry about + // passing this along + if (!isSubMenu) + { + RectI globalbounds(getBounds()); + Point2I globalpoint = localToGlobalCoord(globalbounds.point); + globalbounds.point = globalpoint; + } +} \ No newline at end of file diff --git a/Engine/source/gui/editor/guiPopupMenuCtrl.h b/Engine/source/gui/editor/guiPopupMenuCtrl.h new file mode 100644 index 000000000..c26fa855d --- /dev/null +++ b/Engine/source/gui/editor/guiPopupMenuCtrl.h @@ -0,0 +1,85 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#pragma once + +#ifndef GUI_POPUP_MENU_CTRL_H +#define GUI_POPUP_MENU_CTRL_H + +#ifndef _GUITEXTLISTCTRL_H_ +#include "gui/controls/guiTextListCtrl.h" +#endif + +#ifndef _GUIMENUBAR_H_ +#include "gui/editor/guiMenuBar.h" +#endif + +#ifndef _POPUPMENU_H_ +#include "platform/menus/popupMenu.h" +#endif + +class GuiPopupMenuBackgroundCtrl; + +class GuiPopupMenuTextListCtrl : public GuiTextListCtrl +{ + friend class GuiPopupMenuBackgroundCtrl; + +private: + typedef GuiTextListCtrl Parent; + + GuiPopupMenuBackgroundCtrl* mBackground; + +public: + bool isSubMenu; // Indicates that this text list is in a submenu + Point2I maxBitmapSize; + GuiMenuBar::Menu* mMenu; + GuiMenuBar* mMenuBar; + PopupMenu* mPopup; + + GuiPopupMenuTextListCtrl(); + + // GuiControl overloads: + bool onKeyDown(const GuiEvent &event); + void onMouseDown(const GuiEvent &event); + void onMouseUp(const GuiEvent &event); + void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver); + + virtual void onCellHighlighted(Point2I cell); // Added +}; + +class GuiPopupMenuBackgroundCtrl : public GuiControl +{ + typedef GuiControl Parent; + +protected: + GuiPopupMenuTextListCtrl *mTextList; + +public: + GuiPopupMenuBackgroundCtrl(GuiPopupMenuTextListCtrl* textList); + void onMouseDown(const GuiEvent &event); + void onMouseMove(const GuiEvent &event); + void onMouseDragged(const GuiEvent &event); + + void close(); +}; + +#endif \ No newline at end of file diff --git a/Engine/source/platformSDL/menus/guiPlatformGenericMenuBar.h b/Engine/source/platformSDL/menus/guiPlatformGenericMenuBar.h new file mode 100644 index 000000000..d3ad36e92 --- /dev/null +++ b/Engine/source/platformSDL/menus/guiPlatformGenericMenuBar.h @@ -0,0 +1,29 @@ +#pragma once + +#include "gui/editor/guiMenuBar.h" +#include "platformSDL/menus/PlatformSDLPopupMenuData.h" +#include "platform/menus/popupMenu.h" + +class GuiPlatformGenericMenuBar : public GuiMenuBar +{ + typedef GuiMenuBar Parent; +public: + DECLARE_CONOBJECT(GuiPlatformGenericMenuBar); + + virtual void menuItemSelected(Menu *menu, MenuItem *item) + { + AssertFatal(menu && item, ""); + + PopupMenu *popupMenu = PlatformPopupMenuData::mMenuMap[menu]; + AssertFatal(popupMenu, ""); + + popupMenu->handleSelect(item->id); + + Parent::menuItemSelected(menu, item); + } + +protected: + /// menu id / item id + Map, String> mCmds; + +}; \ No newline at end of file diff --git a/Engine/source/platformSDL/menus/menuBarSDL.cpp b/Engine/source/platformSDL/menus/menuBarSDL.cpp index 211f7bb07..a0ddb2370 100644 --- a/Engine/source/platformSDL/menus/menuBarSDL.cpp +++ b/Engine/source/platformSDL/menus/menuBarSDL.cpp @@ -31,6 +31,8 @@ #include "platformSDL/menus/PlatformSDLPopupMenuData.h" +#include "platformSDL/menus/guiPlatformGenericMenuBar.h" + #ifdef TORQUE_SDL //----------------------------------------------------------------------------- @@ -44,30 +46,6 @@ Map PlatformPopupMenuData::mMenuMap; -class GuiPlatformGenericMenuBar : public GuiMenuBar -{ - typedef GuiMenuBar Parent; -public: - DECLARE_CONOBJECT(GuiPlatformGenericMenuBar); - - virtual void menuItemSelected(Menu *menu, MenuItem *item) - { - AssertFatal(menu && item, ""); - - PopupMenu *popupMenu = PlatformPopupMenuData::mMenuMap[ menu ]; - AssertFatal(popupMenu, ""); - - popupMenu->handleSelect( item->id ); - - Parent::menuItemSelected(menu, item); - } - -protected: - /// menu id / item id - Map, String> mCmds; - -}; - IMPLEMENT_CONOBJECT(GuiPlatformGenericMenuBar); //----------------------------------------------------------------------------- diff --git a/Engine/source/platformSDL/menus/popupMenuSDL.cpp b/Engine/source/platformSDL/menus/popupMenuSDL.cpp index 3d196e1a2..154e16f32 100644 --- a/Engine/source/platformSDL/menus/popupMenuSDL.cpp +++ b/Engine/source/platformSDL/menus/popupMenuSDL.cpp @@ -23,7 +23,7 @@ #ifdef TORQUE_SDL #include "platform/menus/popupMenu.h" -#include "platform/menus//menuBar.h" +#include "platform/menus/menuBar.h" #include "console/consoleTypes.h" #include "gui/core/guiCanvas.h" #include "core/util/safeDelete.h" @@ -37,10 +37,25 @@ #include "platformSDL/menus/PlatformSDLPopupMenuData.h" #include "console/engineAPI.h" +#include "platformSDL/menus/guiPlatformGenericMenuBar.h" +#include "gui/editor/guiPopupMenuCtrl.h" + ////////////////////////////////////////////////////////////////////////// // Platform Menu Data ////////////////////////////////////////////////////////////////////////// +GuiPlatformGenericMenuBar* findMenuBarCtrl() +{ + GuiControl* control; + Sim::findObject("PlatformGenericMenubar", control); + AssertFatal(control, ""); + if (!control) + return NULL; + GuiPlatformGenericMenuBar* menuBar; + menuBar = dynamic_cast(control->findObjectByInternalName(StringTable->insert("menubar"), true)); + AssertFatal(menuBar, ""); + return menuBar; +} ////////////////////////////////////////////////////////////////////////// @@ -215,8 +230,133 @@ bool PopupMenu::handleSelect(U32 command, const char *text /* = NULL */) void PopupMenu::showPopup(GuiCanvas *owner, S32 x /* = -1 */, S32 y /* = -1 */) { - if(owner == NULL || isAttachedToMenuBar()) + if(owner == NULL) return; + + GuiControl* editorGui; + Sim::findObject("EditorGui", editorGui); + + if (editorGui) + { + GuiPopupMenuTextListCtrl* textList; + GuiPopupMenuBackgroundCtrl* backgroundCtrl; + Sim::findObject("PopUpMenuControl", backgroundCtrl); + + GuiControlProfile* profile; + Sim::findObject("GuiMenubarProfile", profile); + + if (!profile) + return; + + if (!backgroundCtrl) + { + textList = new GuiPopupMenuTextListCtrl(); + + textList->registerObject(); + + backgroundCtrl = new GuiPopupMenuBackgroundCtrl(textList); + + backgroundCtrl->registerObject("PopUpMenuControl"); + + textList->setControlProfile(profile); + + backgroundCtrl->addObject(textList); + } + else + { + textList = dynamic_cast(backgroundCtrl->first()); + } + + if (!backgroundCtrl || !textList) + return; + + owner->pushDialogControl(backgroundCtrl, 10); + + backgroundCtrl->setExtent(editorGui->getExtent()); + + textList->clear(); + textList->mMenu = mData->mMenuGui; + textList->mMenuBar = findMenuBarCtrl(); + textList->mPopup = this; + + S32 textWidth = 0, width = 0; + S32 acceleratorWidth = 0; + GFont *font = profile->mFont; + + Point2I maxBitmapSize = Point2I(0, 0); + + S32 numBitmaps = profile->mBitmapArrayRects.size(); + if (numBitmaps) + { + RectI *bitmapBounds = profile->mBitmapArrayRects.address(); + for (S32 i = 0; i < numBitmaps; i++) + { + if (bitmapBounds[i].extent.x > maxBitmapSize.x) + maxBitmapSize.x = bitmapBounds[i].extent.x; + if (bitmapBounds[i].extent.y > maxBitmapSize.y) + maxBitmapSize.y = bitmapBounds[i].extent.y; + } + } + + for (GuiMenuBar::MenuItem *walk = mData->mMenuGui->firstMenuItem; walk; walk = walk->nextMenuItem) + { + if (!walk->visible) + continue; + + S32 iTextWidth = font->getStrWidth(walk->text); + S32 iAcceleratorWidth = walk->accelerator ? font->getStrWidth(walk->accelerator) : 0; + + if (iTextWidth > textWidth) + textWidth = iTextWidth; + if (iAcceleratorWidth > acceleratorWidth) + acceleratorWidth = iAcceleratorWidth; + } + width = textWidth + acceleratorWidth + maxBitmapSize.x * 2 + 2 + 4; + + textList->setCellSize(Point2I(width, font->getHeight() + 2)); + textList->clearColumnOffsets(); + textList->addColumnOffset(-1); // add an empty column in for the bitmap index. + textList->addColumnOffset(maxBitmapSize.x + 1); + textList->addColumnOffset(maxBitmapSize.x + 1 + textWidth + 4); + + U32 entryCount = 0; + + for (GuiMenuBar::MenuItem *walk = mData->mMenuGui->firstMenuItem; walk; walk = walk->nextMenuItem) + { + if (!walk->visible) + continue; + + char buf[512]; + + // If this menu item is a submenu, then set the isSubmenu to 2 to indicate + // an arrow should be drawn. Otherwise set the isSubmenu normally. + char isSubmenu = 1; + if (walk->isSubmenu) + isSubmenu = 2; + + char bitmapIndex = 1; + if (walk->bitmapIndex >= 0 && (walk->bitmapIndex * 3 <= profile->mBitmapArrayRects.size())) + bitmapIndex = walk->bitmapIndex + 2; + dSprintf(buf, sizeof(buf), "%c%c\t%s\t%s", bitmapIndex, isSubmenu, walk->text, walk->accelerator ? walk->accelerator : ""); + textList->addEntry(entryCount, buf); + + if (!walk->enabled) + textList->setEntryActive(entryCount, false); + + entryCount++; + } + + Point2I pos = owner->getCursorPos(); + textList->setPosition(pos); + + //nudge in if we'd overshoot the screen + S32 widthDiff = (textList->getPosition().x + textList->getExtent().x) - backgroundCtrl->getWidth(); + if (widthDiff > 0) + { + Point2I popupPos = textList->getPosition(); + textList->setPosition(popupPos.x - widthDiff, popupPos.y); + } + } } ////////////////////////////////////////////////////////////////////////// From 906cc0ef3979b218d2f69ee1c1c338fbbe985ec5 Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 4 Jul 2016 16:02:49 -0500 Subject: [PATCH 2/3] Forgot copyright header. --- .../menus/guiPlatformGenericMenuBar.h | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Engine/source/platformSDL/menus/guiPlatformGenericMenuBar.h b/Engine/source/platformSDL/menus/guiPlatformGenericMenuBar.h index d3ad36e92..b2129a8b1 100644 --- a/Engine/source/platformSDL/menus/guiPlatformGenericMenuBar.h +++ b/Engine/source/platformSDL/menus/guiPlatformGenericMenuBar.h @@ -1,3 +1,25 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + #pragma once #include "gui/editor/guiMenuBar.h" From 51049b6e8ccf791c17ea623d02eca6e33d771e6b Mon Sep 17 00:00:00 2001 From: Areloch Date: Wed, 6 Jul 2016 00:46:16 -0500 Subject: [PATCH 3/3] Fixes the member-of-class check order to properly sort the context. Also fixes a bug with the spacer entries being filtered from the popup menu, which threw off the selection. --- .../source/platformSDL/menus/popupMenuSDL.cpp | 4 ++- .../tools/worldEditor/scripts/EditorGui.ed.cs | 32 +++++++++---------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Engine/source/platformSDL/menus/popupMenuSDL.cpp b/Engine/source/platformSDL/menus/popupMenuSDL.cpp index 154e16f32..788d7c88e 100644 --- a/Engine/source/platformSDL/menus/popupMenuSDL.cpp +++ b/Engine/source/platformSDL/menus/popupMenuSDL.cpp @@ -99,7 +99,9 @@ void PopupMenu::createPlatformMenu() S32 PopupMenu::insertItem(S32 pos, const char *title, const char* accelerator, const char* cmd) { GuiMenuBar::MenuItem *item = GuiMenuBar::findMenuItem( mData->mMenuGui, title ); - if(item) + + //We'll make a special exception for the spacer items + if(item && dStrcmp(title, "")) { setItem( pos, title, accelerator, cmd); return pos; diff --git a/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs index f9ab055af..6321e44aa 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs @@ -1619,7 +1619,7 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj ) } // Open context menu if this is a SimGroup - else if( %obj.isMemberOfClass( "SimGroup" ) ) + else if( !%obj.isMemberOfClass( "SceneObject" ) ) { %popup = ETSimGroupContextPopup; if( !isObject( %popup ) ) @@ -1643,20 +1643,6 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj ) object = -1; }; - - if(%obj.isMemberOfClass("Entity")) - { - %popup = ETEntityContextPopup; - if( !isObject( %popup ) ) - %popup = new PopupMenu( ETEntityContextPopup : ETSimGroupContextPopup ) - { - superClass = "MenuBuilder"; - isPopup = "1"; - - item[ 12 ] = "-"; - item[ 13 ] = "Convert to Game Object" TAB "" TAB "EWorldEditor.createGameObject( %this.object );"; - }; - } %popup.object = %obj; @@ -1689,9 +1675,23 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj ) object = -1; }; + + if(%obj.isMemberOfClass("Entity")) + { + %popup = ETEntityContextPopup; + if( !isObject( %popup ) ) + %popup = new PopupMenu( ETEntityContextPopup : ETSimGroupContextPopup ) + { + superClass = "MenuBuilder"; + isPopup = "1"; + + item[ 12 ] = "-"; + item[ 13 ] = "Convert to Game Object" TAB "" TAB "EWorldEditor.createGameObject( %this.object );"; + }; + } // Specialized version for ConvexShapes. - if( %obj.isMemberOfClass( "ConvexShape" ) ) + else if( %obj.isMemberOfClass( "ConvexShape" ) ) { %popup = ETConvexShapeContextPopup; if( !isObject( %popup ) )