Ver Fonte

Tooltips are functional

BearishSun há 10 anos atrás
pai
commit
d9cc702b66

+ 113 - 104
BansheeEngine/Include/BsDropDownAreaPlacement.h

@@ -1,105 +1,114 @@
-#pragma once
-
-#include "BsPrerequisites.h"
-#include "BsVector2I.h"
-#include "BsRect2I.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Determines how will the drop down box be positioned. Usually the system will attempt to position
-	 * 			the drop box in a way so all elements can fit, and this class allows you to specify some limitations
-	 * 			on how that works. 
-	 * 			
-	 * @note	For example, list boxes usually want drop down boxes to be placed above or below them, while
-	 * 			context menus may want to have them placed around a single point in any direction.
-	 */
-	class BS_EXPORT DropDownAreaPlacement
-	{
-	public:
-		/**
-		 * @brief	Determines how will the drop down box be positioned.
-		 */
-		enum class Type
-		{
-			Position,
-			BoundsVert,
-			BoundsHorz
-		};
-
-		/**
-		 * @brief	Preferred horizontal direction of the placement bounds, either
-		 *			to the left or to the right of the wanted position/bounds.
-		 */
-		enum class HorzDir
-		{
-			Left, Right
-		};
-
-		/**
-		 * @brief	Preferred horizontal direction of the placement bounds, either
-		 *			upward or downward of the wanted position/bounds.
-		 */
-		enum class VertDir
-		{
-			Up, Down
-		};
-
-		DropDownAreaPlacement() { }
-
-		/**
-		 * @brief	Drop down box will be placed at the specified position. By default the system
-		 * 			prefers the top left corner of the box to correspond to the position, but if
-		 * 			other corners offer more space for the contents, those will be used instead.
-		 */
-		static DropDownAreaPlacement aroundPosition(const Vector2I& position);
-
-		/**
-		 * @brief	Drop down box will be placed at the specified bounds. Box will be horizontally aligned to the left
-		 * 			of the provided bounds. Vertically system prefers placing the box at the bottom of the bounds, but may choose
-		 * 			to align it with the top of the bounds if it offers more space for the contents.
-		 */
-		static DropDownAreaPlacement aroundBoundsVert(const Rect2I& bounds);
-		
-		/**
-		 * @brief	Drop down box will be placed at the specified bounds. Box will be vertically aligned to the top
-		 * 			of the provided bounds. Horizontally system prefers placing the box at the right of the bounds, but may choose
-		 * 			to align it with the left of the bounds if it offers more space for the contents.
-		 */
-		static DropDownAreaPlacement aroundBoundsHorz(const Rect2I& bounds);
-
-		/**
-		 * @brief	Returns drop down box positioning type.
-		 */
-		Type getType() const { return mType; }
-
-		/**
-		 * @brief	Returns bounds around which to position the drop down box
-		 *			if one of the bounds positioning types is used.
-		 */
-		const Rect2I& getBounds() const { return mBounds; }
-
-		/**
-		 * @brief	Returns position around which to position the drop down box
-		 *			if position positioning type is used.
-		 */
-		const Vector2I& getPosition() const { return mPosition; }
-
-		/**
-		 * @brief	Calculates the optimal bounds to place an element of the specified size, within
-		 *			the available area using the internal data as a guide.
-		 *
-		 * @param	width	Width of the element to try to position, in pixels.
-		 * @param	height	Height of the element to try to position, in pixels.
-		 * @param	Rect2I	Available area to try to position the element in, in pixels.
-		 * @param	horzDir	Output parameter that signals the preferred horizontal direction of the bounds (left or right).
-		 * @param	vertDir	Output parameter that signals the preferred vertical direction of the bounds (up or down).
-		 */
-		Rect2I getOptimalBounds(UINT32 width, UINT32 height, const Rect2I& availableArea, HorzDir& horzDir, VertDir& vertDir) const;
-
-	private:
-		Type mType;
-		Rect2I mBounds;
-		Vector2I mPosition;
-	};
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsVector2I.h"
+#include "BsRect2I.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Determines how will the drop down box be positioned. Usually the system will attempt to position
+	 * 			the drop box in a way so all elements can fit, and this class allows you to specify some limitations
+	 * 			on how that works. 
+	 * 			
+	 * @note	For example, list boxes usually want drop down boxes to be placed above or below them, while
+	 * 			context menus may want to have them placed around a single point in any direction.
+	 */
+	class BS_EXPORT DropDownAreaPlacement
+	{
+	public:
+		/**
+		 * @brief	Determines how will the drop down box be positioned.
+		 */
+		enum class Type
+		{
+			Position,
+			BoundsVert,
+			BoundsHorz,
+			BoundsAll
+		};
+
+		/**
+		 * @brief	Preferred horizontal direction of the placement bounds, either
+		 *			to the left or to the right of the wanted position/bounds.
+		 */
+		enum class HorzDir
+		{
+			Left, Right
+		};
+
+		/**
+		 * @brief	Preferred horizontal direction of the placement bounds, either
+		 *			upward or downward of the wanted position/bounds.
+		 */
+		enum class VertDir
+		{
+			Up, Down
+		};
+
+		DropDownAreaPlacement() { }
+
+		/**
+		 * @brief	Drop down box will be placed at the specified position. By default the system
+		 * 			prefers the top left corner of the box to correspond to the position, but if
+		 * 			other corners offer more space for the contents, those will be used instead.
+		 */
+		static DropDownAreaPlacement aroundPosition(const Vector2I& position);
+
+		/**
+		 * @brief	Drop down box will be placed at the specified bounds. Box will be horizontally aligned to the left
+		 * 			of the provided bounds. Vertically system prefers placing the box at the bottom of the bounds, but may choose
+		 * 			to align it with the top of the bounds if it offers more space for the contents.
+		 */
+		static DropDownAreaPlacement aroundBoundsVert(const Rect2I& bounds);
+		
+		/**
+		 * @brief	Drop down box will be placed at the specified bounds. Box will be vertically aligned to the top
+		 * 			of the provided bounds. Horizontally system prefers placing the box at the right of the bounds, but may choose
+		 * 			to align it with the left of the bounds if it offers more space for the contents.
+		 */
+		static DropDownAreaPlacement aroundBoundsHorz(const Rect2I& bounds);
+
+		/**
+		 * @brief	Drop down box will be placed at the specified bounds. Box will be vertically aligned to the top or bottom
+		 * 			of the provided bounds, with bottom being preferred. Horizontally system prefers placing the box at the 
+		 *			right of the bounds, but may choose to align it with the left of the bounds if it offers more space for 
+		 *			the contents.
+		 */
+		static DropDownAreaPlacement aroundBounds(const Rect2I& bounds);
+
+		/**
+		 * @brief	Returns drop down box positioning type.
+		 */
+		Type getType() const { return mType; }
+
+		/**
+		 * @brief	Returns bounds around which to position the drop down box
+		 *			if one of the bounds positioning types is used.
+		 */
+		const Rect2I& getBounds() const { return mBounds; }
+
+		/**
+		 * @brief	Returns position around which to position the drop down box
+		 *			if position positioning type is used.
+		 */
+		const Vector2I& getPosition() const { return mPosition; }
+
+		/**
+		 * @brief	Calculates the optimal bounds to place an element of the specified size, within
+		 *			the available area using the internal data as a guide.
+		 *
+		 * @param	width	Width of the element to try to position, in pixels.
+		 * @param	height	Height of the element to try to position, in pixels.
+		 * @param	Rect2I	Available area to try to position the element in, in pixels.
+		 * @param	horzDir	Output parameter that signals the preferred horizontal direction of the bounds (left or right).
+		 * @param	vertDir	Output parameter that signals the preferred vertical direction of the bounds (up or down).
+		 */
+		Rect2I getOptimalBounds(UINT32 width, UINT32 height, const Rect2I& availableArea, HorzDir& horzDir, VertDir& vertDir) const;
+
+	private:
+		Type mType;
+		Rect2I mBounds;
+		Vector2I mPosition;
+	};
 }
 }

+ 1 - 0
BansheeEngine/Include/BsGUITooltip.h

@@ -29,5 +29,6 @@ namespace BansheeEngine
 
 
 	private:
 	private:
 		static const UINT32 TOOLTIP_WIDTH;
 		static const UINT32 TOOLTIP_WIDTH;
+		static const UINT32 CURSOR_SIZE;
 	};
 	};
 }
 }

+ 132 - 117
BansheeEngine/Source/BsDropDownAreaPlacement.cpp

@@ -1,118 +1,133 @@
-#include "BsDropDownAreaPlacement.h"
-#include "BsDebug.h"
-
-namespace BansheeEngine
-{
-	DropDownAreaPlacement DropDownAreaPlacement::aroundPosition(const Vector2I& position)
-	{
-		DropDownAreaPlacement instance;
-		instance.mType = Type::Position;
-		instance.mPosition = position;
-
-		return instance;
-	}
-
-	DropDownAreaPlacement DropDownAreaPlacement::aroundBoundsVert(const Rect2I& bounds)
-	{
-		DropDownAreaPlacement instance;
-		instance.mType = Type::BoundsVert;
-		instance.mBounds = bounds;
-
-		return instance;
-	}
-
-	DropDownAreaPlacement DropDownAreaPlacement::aroundBoundsHorz(const Rect2I& bounds)
-	{
-		DropDownAreaPlacement instance;
-		instance.mType = Type::BoundsHorz;
-		instance.mBounds = bounds;
-
-		return instance;
-	}
-
-	Rect2I DropDownAreaPlacement::getOptimalBounds(UINT32 width, UINT32 height, const Rect2I& availableArea, HorzDir& horzDir, VertDir& vertDir) const
-	{
-		Rect2I output;
-
-		int potentialLeftStart = 0;
-		int potentialRightStart = 0;
-		int potentialTopStart = 0;
-		int potentialBottomStart = 0;
-
-		switch (getType())
-		{
-		case DropDownAreaPlacement::Type::Position:
-			potentialLeftStart = potentialRightStart = getPosition().x;
-			potentialTopStart = potentialBottomStart = getPosition().y;
-			break;
-		case DropDownAreaPlacement::Type::BoundsHorz:
-			potentialRightStart = getBounds().x;
-			potentialLeftStart = getBounds().x + getBounds().width;
-			potentialBottomStart = getBounds().y + getBounds().height;
-			potentialTopStart = getBounds().y;
-			break;
-		case DropDownAreaPlacement::Type::BoundsVert:
-			potentialRightStart = getBounds().x + getBounds().width;
-			potentialLeftStart = getBounds().x;
-			potentialBottomStart = getBounds().y;
-			potentialTopStart = getBounds().y + getBounds().height;
-			break;
-		}
-
-		// Determine x position and whether to align to left or right side of the drop down list
-		UINT32 availableRightwardWidth = (UINT32)std::max(0, (availableArea.x + availableArea.width) - potentialRightStart);
-		UINT32 availableLeftwardWidth = (UINT32)std::max(0, potentialLeftStart - availableArea.x);
-
-		//// Prefer right if possible
-		if (width <= availableRightwardWidth)
-		{
-			output.x = potentialRightStart;
-			output.width = width;
-			horzDir = HorzDir::Right;
-		}
-		else
-		{
-			if (availableRightwardWidth >= availableLeftwardWidth)
-			{
-				output.x = potentialRightStart;
-				output.width = std::min(width, availableRightwardWidth);
-				horzDir = HorzDir::Right;
-			}
-			else
-			{
-				output.x = potentialLeftStart - std::min(width, availableLeftwardWidth);
-				output.width = std::min(width, availableLeftwardWidth);
-				horzDir = HorzDir::Left;
-			}
-		}
-
-		// Determine y position and whether to open upward or downward
-		UINT32 availableDownwardHeight = (UINT32)std::max(0, (availableArea.y + availableArea.height) - potentialBottomStart);
-		UINT32 availableUpwardHeight = (UINT32)std::max(0, potentialTopStart - availableArea.y);
-
-		//// Prefer down if possible
-		if (height <= availableDownwardHeight)
-		{
-			output.y = potentialBottomStart;
-			output.height = height;
-			vertDir = VertDir::Down;
-		}
-		else
-		{
-			if (availableDownwardHeight >= availableUpwardHeight)
-			{
-				output.y = potentialBottomStart;
-				output.height = std::min(height, availableDownwardHeight);;
-				vertDir = VertDir::Down;
-			}
-			else
-			{
-				output.y = potentialTopStart - (INT32)std::min(height, availableUpwardHeight);
-				output.height = std::min(height, availableUpwardHeight);
-				vertDir = VertDir::Up;
-			}
-		}
-
-		return output;
-	}
+#include "BsDropDownAreaPlacement.h"
+#include "BsDebug.h"
+
+namespace BansheeEngine
+{
+	DropDownAreaPlacement DropDownAreaPlacement::aroundPosition(const Vector2I& position)
+	{
+		DropDownAreaPlacement instance;
+		instance.mType = Type::Position;
+		instance.mPosition = position;
+
+		return instance;
+	}
+
+	DropDownAreaPlacement DropDownAreaPlacement::aroundBoundsVert(const Rect2I& bounds)
+	{
+		DropDownAreaPlacement instance;
+		instance.mType = Type::BoundsVert;
+		instance.mBounds = bounds;
+
+		return instance;
+	}
+
+	DropDownAreaPlacement DropDownAreaPlacement::aroundBoundsHorz(const Rect2I& bounds)
+	{
+		DropDownAreaPlacement instance;
+		instance.mType = Type::BoundsHorz;
+		instance.mBounds = bounds;
+
+		return instance;
+	}
+
+	DropDownAreaPlacement DropDownAreaPlacement::aroundBounds(const Rect2I& bounds)
+	{
+		DropDownAreaPlacement instance;
+		instance.mType = Type::BoundsAll;
+		instance.mBounds = bounds;
+
+		return instance;
+	}
+
+	Rect2I DropDownAreaPlacement::getOptimalBounds(UINT32 width, UINT32 height, const Rect2I& availableArea, HorzDir& horzDir, VertDir& vertDir) const
+	{
+		Rect2I output;
+
+		int potentialLeftStart = 0;
+		int potentialRightStart = 0;
+		int potentialTopStart = 0;
+		int potentialBottomStart = 0;
+
+		switch (getType())
+		{
+		case DropDownAreaPlacement::Type::Position:
+			potentialLeftStart = potentialRightStart = getPosition().x;
+			potentialTopStart = potentialBottomStart = getPosition().y;
+			break;
+		case DropDownAreaPlacement::Type::BoundsHorz:
+			potentialRightStart = getBounds().x;
+			potentialLeftStart = getBounds().x + getBounds().width;
+			potentialBottomStart = getBounds().y + getBounds().height;
+			potentialTopStart = getBounds().y;
+			break;
+		case DropDownAreaPlacement::Type::BoundsVert:
+			potentialRightStart = getBounds().x + getBounds().width;
+			potentialLeftStart = getBounds().x;
+			potentialBottomStart = getBounds().y;
+			potentialTopStart = getBounds().y + getBounds().height;
+			break;
+		case DropDownAreaPlacement::Type::BoundsAll:
+			potentialRightStart = getBounds().x + getBounds().width;
+			potentialLeftStart = getBounds().x;
+			potentialBottomStart = getBounds().y + getBounds().height;
+			potentialTopStart = getBounds().y;
+			break;
+		}
+
+		// Determine x position and whether to align to left or right side of the drop down list
+		UINT32 availableRightwardWidth = (UINT32)std::max(0, (availableArea.x + availableArea.width) - potentialRightStart);
+		UINT32 availableLeftwardWidth = (UINT32)std::max(0, potentialLeftStart - availableArea.x);
+
+		//// Prefer right if possible
+		if (width <= availableRightwardWidth)
+		{
+			output.x = potentialRightStart;
+			output.width = width;
+			horzDir = HorzDir::Right;
+		}
+		else
+		{
+			if (availableRightwardWidth >= availableLeftwardWidth)
+			{
+				output.x = potentialRightStart;
+				output.width = std::min(width, availableRightwardWidth);
+				horzDir = HorzDir::Right;
+			}
+			else
+			{
+				output.x = potentialLeftStart - std::min(width, availableLeftwardWidth);
+				output.width = std::min(width, availableLeftwardWidth);
+				horzDir = HorzDir::Left;
+			}
+		}
+
+		// Determine y position and whether to open upward or downward
+		UINT32 availableDownwardHeight = (UINT32)std::max(0, (availableArea.y + availableArea.height) - potentialBottomStart);
+		UINT32 availableUpwardHeight = (UINT32)std::max(0, potentialTopStart - availableArea.y);
+
+		//// Prefer down if possible
+		if (height <= availableDownwardHeight)
+		{
+			output.y = potentialBottomStart;
+			output.height = height;
+			vertDir = VertDir::Down;
+		}
+		else
+		{
+			if (availableDownwardHeight >= availableUpwardHeight)
+			{
+				output.y = potentialBottomStart;
+				output.height = std::min(height, availableDownwardHeight);;
+				vertDir = VertDir::Down;
+			}
+			else
+			{
+				output.y = potentialTopStart - (INT32)std::min(height, availableUpwardHeight);
+				output.height = std::min(height, availableUpwardHeight);
+				vertDir = VertDir::Up;
+			}
+		}
+
+		return output;
+	}
 }
 }

+ 23 - 21
BansheeEngine/Source/BsGUIManager.cpp

@@ -95,6 +95,7 @@ namespace BansheeEngine
 		mDragEndedConn = DragAndDropManager::instance().onDragEnded.connect(std::bind(&GUIManager::onMouseDragEnded, this, _1, _2));
 		mDragEndedConn = DragAndDropManager::instance().onDragEnded.connect(std::bind(&GUIManager::onMouseDragEnded, this, _1, _2));
 
 
 		GUIDropDownBoxManager::startUp();
 		GUIDropDownBoxManager::startUp();
+		GUITooltipManager::startUp();
 
 
 		mVertexDesc = bs_shared_ptr_new<VertexDataDesc>();
 		mVertexDesc = bs_shared_ptr_new<VertexDataDesc>();
 		mVertexDesc->addVertElem(VET_FLOAT2, VES_POSITION);
 		mVertexDesc->addVertElem(VET_FLOAT2, VES_POSITION);
@@ -111,6 +112,7 @@ namespace BansheeEngine
 
 
 	GUIManager::~GUIManager()
 	GUIManager::~GUIManager()
 	{
 	{
+		GUITooltipManager::shutDown();
 		GUIDropDownBoxManager::shutDown();
 		GUIDropDownBoxManager::shutDown();
 		DragAndDropManager::shutDown();
 		DragAndDropManager::shutDown();
 
 
@@ -232,6 +234,27 @@ namespace BansheeEngine
 	{
 	{
 		DragAndDropManager::instance()._update();
 		DragAndDropManager::instance()._update();
 
 
+		// Show tooltip if needed
+		if (mTooltipElement != nullptr && !mTooltipElement->_isDestroyed())
+		{
+			float diff = gTime().getTime() - mTooltipElementHoverStart;
+			if (diff >= TOOLTIP_HOVER_TIME || gInput().isButtonHeld(BC_LCONTROL) || gInput().isButtonHeld(BC_RCONTROL))
+			{
+				const WString& tooltipText = mTooltipElement->_getTooltip();
+				CGUIWidget* parentWidget = mTooltipElement->_getParentWidget();
+
+				if (!tooltipText.empty() && parentWidget != nullptr)
+				{
+					const RenderWindow* window = getWidgetWindow(*parentWidget);
+					Vector2I windowPos = window->screenToWindowPos(gInput().getPointerPosition());
+
+					GUITooltipManager::instance().show(*parentWidget, windowPos, tooltipText);
+				}
+
+				mTooltipElement = nullptr;
+			}
+		}
+
 		// Update layouts
 		// Update layouts
 		gProfilerCPU().beginSample("UpdateLayout");
 		gProfilerCPU().beginSample("UpdateLayout");
 		for(auto& widgetInfo : mWidgets)
 		for(auto& widgetInfo : mWidgets)
@@ -334,27 +357,6 @@ namespace BansheeEngine
 			}
 			}
 		}
 		}
 
 
-		// Show tooltip if needed
-		if(mTooltipElement != nullptr)
-		{
-			float diff = gTime().getTime() - mTooltipElementHoverStart;
-			if(diff >= TOOLTIP_HOVER_TIME || gInput().isButtonDown(BC_LCONTROL) || gInput().isButtonDown(BC_RCONTROL))
-			{
-				const WString& tooltipText = mTooltipElement->_getTooltip();
-				CGUIWidget* parentWidget = mTooltipElement->_getParentWidget();
-				
-				if (!tooltipText.empty() && parentWidget != nullptr)
-				{
-					const RenderWindow* window = getWidgetWindow(*parentWidget);
-					Vector2I windowPos = window->screenToWindowPos(gInput().getPointerPosition());
-
-					GUITooltipManager::instance().show(*parentWidget, windowPos, tooltipText);
-				}
-
-				mTooltipElement = nullptr;
-			}
-		}
-
 		PROFILE_CALL(updateMeshes(), "UpdateMeshes");
 		PROFILE_CALL(updateMeshes(), "UpdateMeshes");
 
 
 		// Send potentially updated meshes to core for rendering
 		// Send potentially updated meshes to core for rendering

+ 11 - 3
BansheeEngine/Source/BsGUITooltip.cpp

@@ -17,6 +17,7 @@ using namespace std::placeholders;
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	const UINT32 GUITooltip::TOOLTIP_WIDTH = 200;
 	const UINT32 GUITooltip::TOOLTIP_WIDTH = 200;
+	const UINT32 GUITooltip::CURSOR_SIZE = 16;
 
 
 	String GUITooltip::getFrameStyleName()
 	String GUITooltip::getFrameStyleName()
 	{
 	{
@@ -53,7 +54,7 @@ namespace BansheeEngine
 			size.y += backgroundStyle->margins.top + backgroundStyle->margins.bottom;
 			size.y += backgroundStyle->margins.top + backgroundStyle->margins.bottom;
 
 
 			contentOffsetX = backgroundStyle->margins.left;
 			contentOffsetX = backgroundStyle->margins.left;
-			contentOffsetY = backgroundStyle->margins.right;
+			contentOffsetY = backgroundStyle->margins.top;
 		}
 		}
 
 
 		// Content area
 		// Content area
@@ -75,11 +76,18 @@ namespace BansheeEngine
 
 
 		GUILayout* contentLayout = contentPanel->addNewElement<GUILayoutY>();
 		GUILayout* contentLayout = contentPanel->addNewElement<GUILayoutY>();
 		GUILabel* textLabel = contentLayout->addNewElement<GUILabel>(HString(text), 
 		GUILabel* textLabel = contentLayout->addNewElement<GUILabel>(HString(text), 
-			GUIOptions(GUIOption::fixedWidth(TOOLTIP_WIDTH)), BuiltinResources::MultiLineLabelStyle);
+			GUIOptions(GUIOption::fixedWidth(TOOLTIP_WIDTH), GUIOption::flexibleHeight()), 
+			BuiltinResources::MultiLineLabelStyle);
+
+		Rect2I positionBounds;
+		positionBounds.x = position.x;
+		positionBounds.y = position.y;
+		positionBounds.width = CURSOR_SIZE;
+		positionBounds.height = CURSOR_SIZE;
 
 
 		DropDownAreaPlacement::HorzDir horzDir;
 		DropDownAreaPlacement::HorzDir horzDir;
 		DropDownAreaPlacement::VertDir vertDir;
 		DropDownAreaPlacement::VertDir vertDir;
-		DropDownAreaPlacement placement = DropDownAreaPlacement::aroundPosition(position);
+		DropDownAreaPlacement placement = DropDownAreaPlacement::aroundBounds(positionBounds);
 		Rect2I placementBounds = placement.getOptimalBounds((UINT32)size.x, (UINT32)size.y, availableBounds, horzDir, vertDir);
 		Rect2I placementBounds = placement.getOptimalBounds((UINT32)size.x, (UINT32)size.y, availableBounds, horzDir, vertDir);
 
 
 		backgroundPanel->setPosition(placementBounds.x, placementBounds.y);
 		backgroundPanel->setPosition(placementBounds.x, placementBounds.y);

+ 1 - 0
TODO.txt

@@ -17,6 +17,7 @@ Other polish:
   - Add commands for breaking or reverting a scene object 
   - Add commands for breaking or reverting a scene object 
   - Test & finalize undo/redo system
   - Test & finalize undo/redo system
  - Drag and drop of a mesh into Hierarchy doesn't instantiate it
  - Drag and drop of a mesh into Hierarchy doesn't instantiate it
+  - Add OnResourceDropped callback to SceneTreeView and then hook it up on C# side
  - Drag and dropping a prefab onto the scene (or hierarchy) should work the same as with meshes
  - Drag and dropping a prefab onto the scene (or hierarchy) should work the same as with meshes
  - Start editor in fullscreen
  - Start editor in fullscreen
  - If user clears the default shader he has no way of re-assigning it - add default shader to project folder? (needs to be packaged with project)
  - If user clears the default shader he has no way of re-assigning it - add default shader to project folder? (needs to be packaged with project)