(was from earlier failed experiment) git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6211 dfc29bdd-3216-0410-991c-e03cc46cb475
		
			
				
	
	
		
			956 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			956 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (C) 2002-2012 Nikolaus Gebhardt / Gaz Davidson
 | |
| // This file is part of the "Irrlicht Engine".
 | |
| // For conditions of distribution and use, see copyright notice in irrlicht.h
 | |
| 
 | |
| // Thanks to Midnight for all his testing, bug fixes and patches :)
 | |
| 
 | |
| #include "CGUIEditWorkspace.h"
 | |
| #include "IGUIEnvironment.h"
 | |
| #include "IVideoDriver.h"
 | |
| #include "IOSOperator.h"
 | |
| #include "IReadFile.h"
 | |
| #include "IFileSystem.h"
 | |
| #include "IXMLWriter.h"
 | |
| #include "IGUISkin.h"
 | |
| #include "IGUIElementFactory.h"
 | |
| #include "CGUIEditWindow.h"
 | |
| #include "IGUIContextMenu.h"
 | |
| #include "IGUIFileOpenDialog.h"
 | |
| #include "IGUITreeView.h"
 | |
| #include "CGUIAttribute.h"
 | |
| #include "CMemoryReadWriteFile.h"
 | |
| 
 | |
| namespace irr
 | |
| {
 | |
| namespace gui
 | |
| {
 | |
| 
 | |
| //! constructor
 | |
| CGUIEditWorkspace::CGUIEditWorkspace(IGUIEnvironment* environment, s32 id, IGUIElement *parent)
 | |
| : IGUIElement(EGUIET_ELEMENT, environment, parent ? parent : environment->getRootGUIElement(), id, environment->getRootGUIElement()->getAbsolutePosition()),
 | |
| 	CurrentMode(EGUIEDM_SELECT), MouseOverMode(EGUIEDM_SELECT),
 | |
| 	GridSize(10,10), MenuCommandStart(0x3D17), DrawGrid(false), UseGrid(true),
 | |
| 	MouseOverElement(0), SelectedElement(0), EditorWindow(0)
 | |
| {
 | |
| 	#ifdef _DEBUG
 | |
| 	setDebugName("CGUIEditWorkspace");
 | |
| 	#endif
 | |
| 
 | |
| 	// this element is never saved.
 | |
| 	setSubElement(true);
 | |
| 
 | |
| 	// it resizes to fit a resizing window
 | |
| 	setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
 | |
| 
 | |
| 	// Types which we currently can't handle in editor
 | |
| 	// Most of them also just don't make sense in here (like Dialogs)
 | |
| 	// TODO: We should have a way to create context-menus
 | |
| 	UnusableElementTypeFilter.push_back(EGUIET_CONTEXT_MENU);
 | |
| 	UnusableElementTypeFilter.push_back(EGUIET_FILE_OPEN_DIALOG);
 | |
| 	UnusableElementTypeFilter.push_back(EGUIET_COLOR_SELECT_DIALOG);
 | |
| 	UnusableElementTypeFilter.push_back(EGUIET_MESSAGE_BOX);
 | |
| 	UnusableElementTypeFilter.push_back(EGUIET_MODAL_SCREEN);
 | |
| 	UnusableElementTypeFilter.push_back(EGUIET_ELEMENT); // wouldn't do anything, so don't show in menu
 | |
| 	UnusableElementTypeFilter.push_back(EGUIET_ROOT);	// wouldn't do anything, so don't show in menu
 | |
| 
 | |
| 	EditorWindow = (CGUIEditWindow*) Environment->addGUIElement("GUIEditWindow", this);
 | |
| 	if (EditorWindow)
 | |
| 	{
 | |
| 		EditorWindow->grab();
 | |
| 		EditorWindow->setSubElement(true);
 | |
| 
 | |
| 		Environment->setFocus(EditorWindow);
 | |
| 		serializeAttributes(EditorWindow->getOptionEditor()->getAttribs());
 | |
| 		EditorWindow->getOptionEditor()->refreshAttribs();
 | |
| 
 | |
| 		if (EditorWindow->getEnvironmentEditor())
 | |
| 		{
 | |
| 			Environment->serializeAttributes(EditorWindow->getEnvironmentEditor()->getAttribs());
 | |
| 			EditorWindow->getEnvironmentEditor()->refreshAttribs();
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| //! destructor
 | |
| CGUIEditWorkspace::~CGUIEditWorkspace()
 | |
| {
 | |
| 	if (EditorWindow)
 | |
| 		EditorWindow->drop();
 | |
| }
 | |
| 
 | |
| 
 | |
| void CGUIEditWorkspace::setMenuCommandIDStart(s32 id)
 | |
| {
 | |
| 	MenuCommandStart = id;
 | |
| }
 | |
| 
 | |
| CGUIEditWorkspace::EGUIEDIT_MODE CGUIEditWorkspace::getModeFromPos(core::position2di p)
 | |
| {
 | |
| 	if (SelectedElement)
 | |
| 	{
 | |
| 		core::rect<s32>		r = SelectedElement->getAbsolutePosition();
 | |
| 
 | |
| 		if		(TLRect.isPointInside(p))
 | |
| 			return EGUIEDM_RESIZE_TL;
 | |
| 
 | |
| 		else if (TRRect.isPointInside(p))
 | |
| 			return EGUIEDM_RESIZE_TR;
 | |
| 
 | |
| 		else if (BLRect.isPointInside(p) )
 | |
| 			return EGUIEDM_RESIZE_BL;
 | |
| 
 | |
| 		else if (BRRect.isPointInside(p))
 | |
| 			return EGUIEDM_RESIZE_BR;
 | |
| 
 | |
| 		else if (TopRect.isPointInside(p))
 | |
| 			return EGUIEDM_RESIZE_T;
 | |
| 
 | |
| 		else if (BRect.isPointInside(p))
 | |
| 			return EGUIEDM_RESIZE_B;
 | |
| 
 | |
| 		else if (LRect.isPointInside(p))
 | |
| 			return EGUIEDM_RESIZE_L;
 | |
| 
 | |
| 		else if (RRect.isPointInside(p))
 | |
| 			return EGUIEDM_RESIZE_R;
 | |
| 
 | |
| 		else if (getEditableElementFromPoint(SelectedElement, p) == SelectedElement)
 | |
| 			return EGUIEDM_MOVE;
 | |
| 
 | |
| 		else
 | |
| 			return EGUIEDM_SELECT;
 | |
| 	}
 | |
| 
 | |
| 	return EGUIEDM_SELECT;
 | |
| 
 | |
| }
 | |
| 
 | |
| IGUIElement* CGUIEditWorkspace::getEditableElementFromPoint(IGUIElement *start, const core::position2di &point, s32 index )
 | |
| {
 | |
| 	IGUIElement* target = 0;
 | |
| 
 | |
| 	// we have to search from back to front.
 | |
| 
 | |
| 	core::list<IGUIElement*>::ConstIterator it = start->getChildren().getLast();
 | |
| 	s32 count=0;
 | |
| 	while(it != start->getChildren().end())
 | |
| 	{
 | |
| 		target = getEditableElementFromPoint((*it),point);
 | |
| 		if (target)
 | |
| 		{
 | |
| 			if (!target->isSubElement() && !isMyChild(target) && target != this)
 | |
| 			{
 | |
| 				if (index == count)
 | |
| 					return target;
 | |
| 				else
 | |
| 					count++;
 | |
| 			}
 | |
| 			else
 | |
| 				target = 0;
 | |
| 		}
 | |
| 		--it;
 | |
| 	}
 | |
| 
 | |
| 	if (start->getAbsolutePosition().isPointInside(point))
 | |
| 		target = start;
 | |
| 
 | |
| 	return target;
 | |
| }
 | |
| 
 | |
| void CGUIEditWorkspace::setSelectedElement(IGUIElement *sel)
 | |
| {
 | |
| 	IGUIElement* focus = Environment->getFocus();
 | |
| 	// we only give focus back to children
 | |
| 	if (!isMyChild(focus))
 | |
| 		focus = 0;
 | |
| 
 | |
| 	if (SelectedElement != Parent)
 | |
| 	{
 | |
| 		if (SelectedElement != sel && EditorWindow)
 | |
| 		{
 | |
| 			EditorWindow->setSelectedElement(sel);
 | |
| 			SelectedElement = sel;
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 		SelectedElement = 0;
 | |
| 
 | |
| 	if (focus)
 | |
| 		Environment->setFocus(focus);
 | |
| 	else
 | |
| 		Environment->setFocus(this);
 | |
| }
 | |
| 
 | |
| IGUIElement* CGUIEditWorkspace::getSelectedElement()
 | |
| {
 | |
| 	return SelectedElement;
 | |
| }
 | |
| void CGUIEditWorkspace::selectNextSibling()
 | |
| {
 | |
| 	IGUIElement* p=0;
 | |
| 
 | |
| 	if (SelectedElement && SelectedElement->getParent())
 | |
| 		p = SelectedElement->getParent();
 | |
| 	else
 | |
| 		p = Parent;
 | |
| 
 | |
| 	core::list<IGUIElement*>::ConstIterator it = p->getChildren().begin();
 | |
| 	// find selected element
 | |
| 	if (SelectedElement)
 | |
| 		while (*it != SelectedElement)
 | |
| 			++it;
 | |
| 	if (it !=p->getChildren().end())
 | |
| 		++it;
 | |
| 	// find next non sub-element
 | |
| 	while (it != p->getChildren().end() && (*it)->isSubElement())
 | |
| 		++it;
 | |
| 
 | |
| 	if (it != p->getChildren().end())
 | |
| 		setSelectedElement(*it);
 | |
| }
 | |
| void CGUIEditWorkspace::selectPreviousSibling()
 | |
| {
 | |
| 	IGUIElement* p=0;
 | |
| 
 | |
| 	if (SelectedElement && SelectedElement->getParent())
 | |
| 		p = SelectedElement->getParent();
 | |
| 	else
 | |
| 		p = Parent;
 | |
| 
 | |
| 	core::list<IGUIElement*>::ConstIterator it = p->getChildren().getLast();
 | |
| 	// find selected element
 | |
| 	if (SelectedElement)
 | |
| 		while (*it != SelectedElement)
 | |
| 			--it;
 | |
| 	if (it != p->getChildren().end())
 | |
| 		--it;
 | |
| 	// find next non sub-element
 | |
| 	while (it != p->getChildren().end() && (*it)->isSubElement())
 | |
| 		--it;
 | |
| 
 | |
| 	if (it != p->getChildren().end())
 | |
| 		setSelectedElement(*it);
 | |
| }
 | |
| 
 | |
| //! called if an event happened.
 | |
| bool CGUIEditWorkspace::OnEvent(const SEvent &e)
 | |
| {
 | |
| 	IGUIFileOpenDialog* dialog=0;
 | |
| 	switch(e.EventType)
 | |
| 	{
 | |
| 	case ATTRIBEDIT_ATTRIB_CHANGED:
 | |
| 		{
 | |
| 			switch (e.UserEvent.UserData1)
 | |
| 			{
 | |
| 			case EGUIEDCE_ATTRIB_EDITOR:
 | |
| 				{
 | |
| 					// update selected items attributes
 | |
| 					if (SelectedElement)
 | |
| 					{
 | |
| 						SelectedElement->deserializeAttributes(EditorWindow->getAttributeEditor()->getAttribs());
 | |
| 						EditorWindow->updateTree();
 | |
| 					}
 | |
| 					return true;
 | |
| 				}
 | |
| 			case EGUIEDCE_OPTION_EDITOR:
 | |
| 				{
 | |
| 					// update editor options
 | |
| 					deserializeAttributes(EditorWindow->getOptionEditor()->getAttribs());
 | |
| 					return true;
 | |
| 				}
 | |
| 			case EGUIEDCE_ENV_EDITOR:
 | |
| 				{
 | |
| 					// update environment
 | |
| 					Environment->deserializeAttributes(EditorWindow->getEnvironmentEditor()->getAttribs());
 | |
| 					return true;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	case EET_KEY_INPUT_EVENT:
 | |
| 		if (!e.KeyInput.PressedDown)
 | |
| 		{
 | |
| 			switch (e.KeyInput.Key)
 | |
| 			{
 | |
| 			case KEY_DELETE:
 | |
| 				if (SelectedElement)
 | |
| 				{
 | |
| 					IGUIElement* el = SelectedElement;
 | |
| 					setSelectedElement(0);
 | |
| 					MouseOverElement = 0;
 | |
| 					el->remove();
 | |
| 					EditorWindow->updateTree();
 | |
| 				}
 | |
| 				break;
 | |
| 			case KEY_KEY_X:
 | |
| 				if (e.KeyInput.Control && SelectedElement)
 | |
| 				{
 | |
| 					// cut
 | |
| 					CopySelectedElementXML();
 | |
| 					// delete element
 | |
| 					IGUIElement *el = SelectedElement;
 | |
| 					setSelectedElement(0);
 | |
| 					MouseOverElement = 0;
 | |
| 					el->remove();
 | |
| 				}
 | |
| 				break;
 | |
| 			case KEY_KEY_C:
 | |
| 				// copy
 | |
| 				if (e.KeyInput.Control && SelectedElement)
 | |
| 				{
 | |
| 					CopySelectedElementXML();
 | |
| 				}
 | |
| 				break;
 | |
| 			case KEY_KEY_V:
 | |
| 				// paste
 | |
| 				if (e.KeyInput.Control)
 | |
| 				{
 | |
| 					PasteXMLToSelectedElement();
 | |
| 				}
 | |
| 				break;
 | |
| 			default:
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			return true;
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	case EET_MOUSE_INPUT_EVENT:
 | |
| 
 | |
| 		switch(e.MouseInput.Event)
 | |
| 		{
 | |
| 		case EMIE_MOUSE_WHEEL:
 | |
| 			{
 | |
| 				f32 wheel = e.MouseInput.Wheel;
 | |
| 
 | |
| 				if (wheel > 0)
 | |
| 					selectPreviousSibling();
 | |
| 				else
 | |
| 					selectNextSibling();
 | |
| 			}
 | |
| 			break;
 | |
| 		case EMIE_LMOUSE_PRESSED_DOWN:
 | |
| 		{
 | |
| 			core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y);
 | |
| 
 | |
| 			IGUIElement* newSelection = getElementFromPoint(p);
 | |
| 
 | |
| 			if (newSelection != this && isMyChild(newSelection) ) // redirect event
 | |
| 			{
 | |
| 				Environment->setFocus(newSelection);
 | |
| 				return true;
 | |
| 			}
 | |
| 
 | |
| 			// hide the gui editor
 | |
| 			if (EditorWindow)
 | |
| 				EditorWindow->setVisible(false);
 | |
| 
 | |
| 			if (CurrentMode == EGUIEDM_SELECT)
 | |
| 			{
 | |
| 				if (SelectedElement)
 | |
| 				{
 | |
| 					// start moving or dragging
 | |
| 					CurrentMode = getModeFromPos(p);
 | |
| 
 | |
| 					if (CurrentMode == EGUIEDM_MOVE)
 | |
| 						StartMovePos = SelectedElement->getAbsolutePosition().UpperLeftCorner;
 | |
| 
 | |
| 					DragStart = p;
 | |
| 					SelectedArea = SelectedElement->getAbsolutePosition();
 | |
| 				}
 | |
| 
 | |
| 				if (CurrentMode < EGUIEDM_MOVE)
 | |
| 				{
 | |
| 					// selecting an element...
 | |
| 					MouseOverElement = getEditableElementFromPoint(Parent, p);
 | |
| 
 | |
| 					if (MouseOverElement == Parent)
 | |
| 						MouseOverElement = 0;
 | |
| 
 | |
| 					setSelectedElement(MouseOverElement);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			break;
 | |
| 		}
 | |
| 		case EMIE_RMOUSE_PRESSED_DOWN:
 | |
| 			if (CurrentMode == EGUIEDM_SELECT_NEW_PARENT || CurrentMode >= EGUIEDM_MOVE)
 | |
| 			{
 | |
| 				// cancel dragging
 | |
| 				CurrentMode = EGUIEDM_SELECT;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				DragStart = core::position2di(e.MouseInput.X,e.MouseInput.Y);
 | |
| 				// root menu
 | |
| 				IGUIContextMenu* mnu = Environment->addContextMenu(
 | |
| 					core::rect<s32>(e.MouseInput.X, e.MouseInput.Y, e.MouseInput.Y+100, e.MouseInput.Y+100),this);
 | |
| 				mnu->addItem(L"File",-1,true,true);
 | |
| 				mnu->addItem(L"Edit",-1,true,true);
 | |
| 				mnu->addItem(L"View",-1,true,true);
 | |
| 				mnu->addItem(SelectedElement ? L"Add child" : L"Add" ,-1,true,true);
 | |
| 
 | |
| 				// file menu
 | |
| 				IGUIContextMenu* sub = mnu->getSubMenu(0);
 | |
| 				IGUIContextMenu* sub2 =0;
 | |
| 
 | |
| 				sub->addItem(L"New",	MenuCommandStart + EGUIEDMC_FILE_NEW );
 | |
| 				sub->addItem(L"Load...",MenuCommandStart + EGUIEDMC_FILE_LOAD);
 | |
| 				sub->addItem(L"Save...",MenuCommandStart + EGUIEDMC_FILE_SAVE);
 | |
| 
 | |
| 				// edit menu
 | |
| 				sub = mnu->getSubMenu(1);
 | |
| 				sub->addItem(L"Cut (ctrl+x)", MenuCommandStart + EGUIEDMC_CUT_ELEMENT,	(SelectedElement != 0));
 | |
| 				sub->addItem(L"Copy (ctrl+c)", MenuCommandStart + EGUIEDMC_COPY_ELEMENT,	(SelectedElement != 0));
 | |
| 				sub->addItem(L"Paste (ctrl+v)", MenuCommandStart + EGUIEDMC_PASTE_ELEMENT,
 | |
| 					(core::stringc(Environment->getOSOperator()->getTextFromClipboard()) != ""));
 | |
| 				sub->addItem(L"Delete (del)", MenuCommandStart + EGUIEDMC_DELETE_ELEMENT, (SelectedElement != 0));
 | |
| 				sub->addSeparator();
 | |
| 				sub->addItem(L"Set parent",		MenuCommandStart + EGUIEDMC_SET_PARENT,		(SelectedElement != 0));
 | |
| 				sub->addItem(L"Bring to front", MenuCommandStart + EGUIEDMC_BRING_TO_FRONT, (SelectedElement != 0));
 | |
| 				sub->addSeparator();
 | |
| 				sub->addItem(L"Save to XML...", MenuCommandStart + EGUIEDMC_SAVE_ELEMENT,	(SelectedElement != 0));
 | |
| 
 | |
| 				sub = mnu->getSubMenu(2);
 | |
| 				// view menu
 | |
| 				if (EditorWindow)
 | |
| 					sub->addItem(EditorWindow->isVisible() ? L"Hide window" : L"Show window", MenuCommandStart + EGUIEDMC_TOGGLE_EDITOR);
 | |
| 
 | |
| 				sub = mnu->getSubMenu(3);
 | |
| 
 | |
| 				s32 i,j,c=0;
 | |
| 				sub->addItem(L"Default factory",-1,true, true);
 | |
| 
 | |
| 				// add elements from each factory
 | |
| 				for (i=0; u32(i) < Environment->getRegisteredGUIElementFactoryCount(); ++i)
 | |
| 				{
 | |
| 					sub2 = sub->getSubMenu(i);
 | |
| 
 | |
| 					IGUIElementFactory *f = Environment->getGUIElementFactory(i);
 | |
| 
 | |
| 					for (j=0; j< f->getCreatableGUIElementTypeCount(); ++j)
 | |
| 					{
 | |
| 						EGUI_ELEMENT_TYPE type = f->getCreateableGUIElementType(j);
 | |
| 						if ( UnusableElementTypeFilter.linear_search(type) < 0 )
 | |
| 							sub2->addItem(core::stringw(f->getCreateableGUIElementTypeName(j)).c_str(), MenuCommandStart + EGUIEDMC_COUNT + c);
 | |
| 						c++;
 | |
| 					}
 | |
| 
 | |
| 					if (u32(i+1) < Environment->getRegisteredGUIElementFactoryCount())
 | |
| 					{
 | |
| 						core::stringw strFact;
 | |
| 						strFact = L"Factory ";
 | |
| 						strFact += i+1;
 | |
| 						sub->addItem(strFact.c_str(),-1, true, true);
 | |
| 					}
 | |
| 				}
 | |
| 				sub->addSeparator();
 | |
| 				sub->addItem(L"From XML...", MenuCommandStart + EGUIEDMC_INSERT_XML);
 | |
| 
 | |
| 				// set focus to menu
 | |
| 				Environment->setFocus(mnu);
 | |
| 
 | |
| 			}
 | |
| 			break;
 | |
| 		case EMIE_LMOUSE_LEFT_UP:
 | |
| 
 | |
| 			// make window visible again
 | |
| 			if (EditorWindow)
 | |
| 				EditorWindow->setVisible(true);
 | |
| 			if (CurrentMode == EGUIEDM_SELECT_NEW_PARENT)
 | |
| 			{
 | |
| 				if (SelectedElement)
 | |
| 				{
 | |
| 					MouseOverElement = getEditableElementFromPoint(Parent,
 | |
| 						core::position2di(e.MouseInput.X,e.MouseInput.Y));
 | |
| 					if (MouseOverElement)
 | |
| 					{
 | |
| 						MouseOverElement->addChild(SelectedElement);
 | |
| 						setSelectedElement(0);
 | |
| 						setSelectedElement(SelectedElement);
 | |
| 					}
 | |
| 				}
 | |
| 				CurrentMode = EGUIEDM_SELECT;
 | |
| 			}
 | |
| 			else if (CurrentMode >= EGUIEDM_MOVE)
 | |
| 			{
 | |
| 				IGUIElement *sel = SelectedElement;
 | |
| 				// unselect
 | |
| 				setSelectedElement(0);
 | |
| 
 | |
| 				// move
 | |
| 				core::position2d<s32> p(0,0);
 | |
| 				if (sel->getParent())
 | |
| 					p = sel->getParent()->getAbsolutePosition().UpperLeftCorner;
 | |
| 
 | |
| 				sel->setRelativePosition(SelectedArea - p);
 | |
| 
 | |
| 				// select
 | |
| 				setSelectedElement(sel);
 | |
| 
 | |
| 				// reset selection mode...
 | |
| 				CurrentMode = EGUIEDM_SELECT;
 | |
| 			}
 | |
| 			break;
 | |
| 		case EMIE_MOUSE_MOVED:
 | |
| 			// always on top
 | |
| 			Parent->bringToFront(this);
 | |
| 
 | |
| 			// if selecting
 | |
| 			if (CurrentMode == EGUIEDM_SELECT || CurrentMode == EGUIEDM_SELECT_NEW_PARENT)
 | |
| 			{
 | |
| 
 | |
| 				core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y);
 | |
| 
 | |
| 				// highlight the element that the mouse is over
 | |
| 				MouseOverElement = getEditableElementFromPoint(Parent, p);
 | |
| 				if (MouseOverElement == Parent)
 | |
| 				{
 | |
| 					MouseOverElement = 0;
 | |
| 				}
 | |
| 
 | |
| 				if (CurrentMode == EGUIEDM_SELECT)
 | |
| 				{
 | |
| 					MouseOverMode = getModeFromPos(p);
 | |
| 					if (MouseOverMode > EGUIEDM_MOVE)
 | |
| 					{
 | |
| 						MouseOverElement = SelectedElement;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			else if (CurrentMode == EGUIEDM_MOVE)
 | |
| 			{
 | |
| 				// get difference
 | |
| 				core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y);
 | |
| 				p -= DragStart;
 | |
| 
 | |
| 				// apply to top corner
 | |
| 				p = StartMovePos + p;
 | |
| 				if (UseGrid)
 | |
| 				{
 | |
| 					p.X = (p.X/GridSize.Width)*GridSize.Width;
 | |
| 					p.Y = (p.Y/GridSize.Height)*GridSize.Height;
 | |
| 				}
 | |
| 
 | |
| 				SelectedArea += p - SelectedArea.UpperLeftCorner;
 | |
| 			}
 | |
| 			else if (CurrentMode > EGUIEDM_MOVE)
 | |
| 			{
 | |
| 				// get difference from start position
 | |
| 				core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y);
 | |
| 				if (UseGrid)
 | |
| 				{
 | |
| 					p.X = (p.X/GridSize.Width)*GridSize.Width;
 | |
| 					p.Y = (p.Y/GridSize.Height)*GridSize.Height;
 | |
| 				}
 | |
| 
 | |
| 				switch(CurrentMode)
 | |
| 				{
 | |
| 					case EGUIEDM_RESIZE_T:
 | |
| 						SelectedArea.UpperLeftCorner.Y = p.Y;
 | |
| 						break;
 | |
| 					case EGUIEDM_RESIZE_B:
 | |
| 						SelectedArea.LowerRightCorner.Y = p.Y;
 | |
| 						break;
 | |
| 					case EGUIEDM_RESIZE_L:
 | |
| 						SelectedArea.UpperLeftCorner.X = p.X;
 | |
| 						break;
 | |
| 					case EGUIEDM_RESIZE_R:
 | |
| 						SelectedArea.LowerRightCorner.X = p.X;
 | |
| 						break;
 | |
| 					case EGUIEDM_RESIZE_TL:
 | |
| 						SelectedArea.UpperLeftCorner = p;
 | |
| 						break;
 | |
| 					case EGUIEDM_RESIZE_TR:
 | |
| 						SelectedArea.UpperLeftCorner.Y = p.Y;
 | |
| 						SelectedArea.LowerRightCorner.X = p.X;
 | |
| 						break;
 | |
| 					case EGUIEDM_RESIZE_BL:
 | |
| 						SelectedArea.UpperLeftCorner.X = p.X;
 | |
| 						SelectedArea.LowerRightCorner.Y = p.Y;
 | |
| 						break;
 | |
| 					case EGUIEDM_RESIZE_BR:
 | |
| 						SelectedArea.LowerRightCorner = p;
 | |
| 						break;
 | |
| 					default:
 | |
| 						break;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			break;
 | |
| 		default:
 | |
| 			break;
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	case EET_GUI_EVENT:
 | |
| 		switch(e.GUIEvent.EventType)
 | |
| 		{
 | |
|         case EGET_TREEVIEW_NODE_SELECT:
 | |
|         {
 | |
|             IGUITreeViewNode* eventnode = ((IGUITreeView*)e.GUIEvent.Caller)->getLastEventNode();
 | |
|             if(!eventnode->isRoot())
 | |
|                 setSelectedElement((IGUIElement*)(eventnode->getData()));
 | |
|             break;
 | |
|         }
 | |
| 		// load a gui file
 | |
| 		case EGET_FILE_SELECTED:
 | |
| 		{
 | |
| 			dialog = (IGUIFileOpenDialog*)e.GUIEvent.Caller;
 | |
| 			core::stringc guiFilename(core::stringc(dialog->getFileName()).c_str());
 | |
| 			clearParentElements();
 | |
| 			Environment->loadGUI(guiFilename, Parent);
 | |
| 			EditorWindow->updateTree();
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case EGET_MENU_ITEM_SELECTED:
 | |
| 		{
 | |
| 			IGUIContextMenu *menu = (IGUIContextMenu*)e.GUIEvent.Caller;
 | |
| 			s32 cmdID = menu->getItemCommandId(menu->getSelectedItem()) - MenuCommandStart;
 | |
| 
 | |
| 			IGUIElement* el;
 | |
| 
 | |
| 			switch(cmdID)
 | |
| 			{
 | |
| 
 | |
| 				//! file commands
 | |
| 				case EGUIEDMC_FILE_NEW:
 | |
| 					clearParentElements();
 | |
| 					break;
 | |
| 				case EGUIEDMC_FILE_LOAD:
 | |
| 					Environment->addFileOpenDialog(L"Please select a GUI file to open", false, this);
 | |
| 					break;
 | |
| 				case EGUIEDMC_FILE_SAVE:
 | |
| 					Environment->saveGUI("guiTest.xml");
 | |
| 					break;
 | |
| 
 | |
| 				//! edit menu
 | |
| 				case EGUIEDMC_CUT_ELEMENT:
 | |
| 				{
 | |
| 					CopySelectedElementXML();
 | |
| 					// delete element
 | |
| 					el = SelectedElement;
 | |
| 					setSelectedElement(0);
 | |
| 					MouseOverElement = 0;
 | |
| 					el->remove();
 | |
| 					break;
 | |
| 				}
 | |
| 				case EGUIEDMC_COPY_ELEMENT:
 | |
| 					CopySelectedElementXML();
 | |
| 					break;
 | |
| 				case EGUIEDMC_PASTE_ELEMENT:
 | |
| 					PasteXMLToSelectedElement();
 | |
| 					break;
 | |
| 				case EGUIEDMC_DELETE_ELEMENT:
 | |
| 					el = SelectedElement;
 | |
| 					setSelectedElement(0);
 | |
| 					MouseOverElement = 0;
 | |
| 					el->remove();
 | |
| 					break;
 | |
| 				case EGUIEDMC_SET_PARENT:
 | |
| 					CurrentMode = EGUIEDM_SELECT_NEW_PARENT;
 | |
| 					break;
 | |
| 				case EGUIEDMC_BRING_TO_FRONT:
 | |
| 					if (SelectedElement->getParent())
 | |
| 						SelectedElement->getParent()->bringToFront(SelectedElement);
 | |
| 					break;
 | |
| 
 | |
| 				case EGUIEDMC_SAVE_ELEMENT:
 | |
|                     //TODO: add 'save' dialog.
 | |
| 					Environment->saveGUI("guiTest.xml", SelectedElement ? SelectedElement : Environment->getRootGUIElement() );
 | |
| 					break;
 | |
| 
 | |
| 				//! toggle edit window
 | |
| 				case EGUIEDMC_TOGGLE_EDITOR:
 | |
| 					break;
 | |
| 
 | |
| 				case EGUIEDMC_INSERT_XML:
 | |
| 					Environment->loadGUI("guiTest.xml", SelectedElement ? SelectedElement : Environment->getRootGUIElement() );
 | |
| 					break;
 | |
| 
 | |
| 				default:
 | |
| 					// create element from factory?
 | |
| 					if (cmdID >= EGUIEDMC_COUNT)
 | |
| 					{
 | |
| 
 | |
| 						s32 num = cmdID - EGUIEDMC_COUNT; // get index
 | |
| 						// loop through all factories
 | |
| 						s32 i, c=Environment->getRegisteredGUIElementFactoryCount();
 | |
| 						for (i=0; i<c && num > Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount(); ++i)
 | |
| 						{
 | |
| 							num -= Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount();
 | |
| 						}
 | |
| 						if (num < Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount() )
 | |
| 						{
 | |
| 							core::stringc name = Environment->getGUIElementFactory(i)->getCreateableGUIElementTypeName(num);
 | |
| 							IGUIElement *parentElement = SelectedElement ? SelectedElement : Environment->getRootGUIElement();
 | |
| 							// add it
 | |
| 							IGUIElement *newElement = Environment->getGUIElementFactory(i)->addGUIElement(name.c_str(),parentElement);
 | |
| 							if (newElement)
 | |
| 							{
 | |
| 								core::position2di p = DragStart - parentElement->getAbsolutePosition().UpperLeftCorner;
 | |
| 								newElement->setRelativePosition(core::rect<s32>(p,p+core::position2di(100,100)));
 | |
| 								//Environment->removeFocus(newElement);
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 					break;
 | |
| 				}
 | |
| 				EditorWindow->updateTree();
 | |
| 			}
 | |
| 			return true;
 | |
| 		default:
 | |
| 			break;
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	default:
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	// even if we didn't absorb the event,
 | |
| 	// we never pass events back to the GUI we're editing!
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! draws the element and its children
 | |
| void CGUIEditWorkspace::draw()
 | |
| {
 | |
| 	video::IVideoDriver *driver = Environment->getVideoDriver();
 | |
| 
 | |
| 	if (DrawGrid)
 | |
| 	{
 | |
| 		// draw the grid
 | |
| 
 | |
| 		core::rect<s32> r = getAbsolutePosition();
 | |
| 
 | |
| 		s32 cy = r.UpperLeftCorner.Y;
 | |
| 		while (cy < r.LowerRightCorner.Y)
 | |
| 		{
 | |
| 			s32 cx = r.UpperLeftCorner.X;
 | |
| 			while (cx < r.LowerRightCorner.X)
 | |
| 			{
 | |
| 				driver->draw2DRectangle(video::SColor(40,0,0,90),core::rect<s32>(cx+1,cy+1,GridSize.Width+cx,GridSize.Height+cy));
 | |
| 				cx += GridSize.Width;
 | |
| 			}
 | |
| 			cy += GridSize.Height;
 | |
| 		}
 | |
| 	}
 | |
| 	if (MouseOverElement &&
 | |
| 		MouseOverElement != SelectedElement &&
 | |
| 		MouseOverElement != Parent)
 | |
| 	{
 | |
| 		core::rect<s32> r = MouseOverElement->getAbsolutePosition();
 | |
| 		driver->draw2DRectangle(video::SColor(100,0,0,255), r);
 | |
| 	}
 | |
| 	if (SelectedElement && CurrentMode == EGUIEDM_SELECT)
 | |
| 	{
 | |
| 		driver->draw2DRectangle(video::SColor(100,0,255,0),SelectedElement->getAbsolutePosition());
 | |
| 	}
 | |
| 	if (CurrentMode >= EGUIEDM_MOVE)
 | |
| 	{
 | |
| 		driver->draw2DRectangle(video::SColor(100,255,0,0),SelectedArea);
 | |
| 	}
 | |
| 
 | |
| 	if ( (SelectedElement && CurrentMode >= EGUIEDM_MOVE) ||
 | |
| 		(SelectedElement && MouseOverElement == SelectedElement && MouseOverMode >= EGUIEDM_MOVE) )
 | |
| 	{
 | |
| 		// draw handles for moving
 | |
| 		EGUIEDIT_MODE m = CurrentMode;
 | |
| 		core::rect<s32> r = SelectedArea;
 | |
| 		if (m < EGUIEDM_MOVE)
 | |
| 		{
 | |
| 			m = MouseOverMode;
 | |
| 			r = SelectedElement->getAbsolutePosition();
 | |
| 		}
 | |
| 
 | |
| 		core::position2di d = core::position2di(4,4);
 | |
| 
 | |
| 		TLRect = core::rect<s32>(r.UpperLeftCorner, r.UpperLeftCorner + d );
 | |
| 		TRRect = core::rect<s32>(r.LowerRightCorner.X-4, r.UpperLeftCorner.Y, r.LowerRightCorner.X, r.UpperLeftCorner.Y+4);
 | |
| 		TopRect = core::rect<s32>(r.getCenter().X-2, r.UpperLeftCorner.Y,r.getCenter().X+2, r.UpperLeftCorner.Y+4 );
 | |
| 		BLRect = core::rect<s32>(r.UpperLeftCorner.X, r.LowerRightCorner.Y-4, r.UpperLeftCorner.X+4, r.LowerRightCorner.Y);
 | |
| 		LRect = core::rect<s32>(r.UpperLeftCorner.X,r.getCenter().Y-2, r.UpperLeftCorner.X+4, r.getCenter().Y+2 );
 | |
| 		RRect = core::rect<s32>(r.LowerRightCorner.X-4,r.getCenter().Y-2, r.LowerRightCorner.X, r.getCenter().Y+2 );
 | |
| 		BRRect = core::rect<s32>(r.LowerRightCorner-d, r.LowerRightCorner);
 | |
| 		BRect = core::rect<s32>(r.getCenter().X-2, r.LowerRightCorner.Y-4,r.getCenter().X+2, r.LowerRightCorner.Y );
 | |
| 
 | |
| 		// top left
 | |
| 		if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_RESIZE_L || m == EGUIEDM_RESIZE_TL || m == EGUIEDM_MOVE )
 | |
| 			driver->draw2DRectangle(video::SColor(100,255,255,255), TLRect);
 | |
| 
 | |
| 		if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_RESIZE_R || m == EGUIEDM_RESIZE_TR || m == EGUIEDM_MOVE )
 | |
| 			driver->draw2DRectangle(video::SColor(100,255,255,255), TRRect);
 | |
| 
 | |
| 		if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_MOVE )
 | |
| 			driver->draw2DRectangle(video::SColor(100,255,255,255), TopRect);
 | |
| 
 | |
| 		if (m == EGUIEDM_RESIZE_L || m == EGUIEDM_RESIZE_BL || m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE )
 | |
| 			driver->draw2DRectangle(video::SColor(100,255,255,255), BLRect);
 | |
| 
 | |
| 		if (m == EGUIEDM_RESIZE_L || m == EGUIEDM_MOVE )
 | |
| 			driver->draw2DRectangle(video::SColor(100,255,255,255), LRect);
 | |
| 
 | |
| 		if (m == EGUIEDM_RESIZE_R || m == EGUIEDM_MOVE )
 | |
| 			driver->draw2DRectangle(video::SColor(100,255,255,255), RRect);
 | |
| 
 | |
| 		if (m == EGUIEDM_RESIZE_R || m == EGUIEDM_RESIZE_BR || m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE )
 | |
| 			driver->draw2DRectangle(video::SColor(100,255,255,255), BRRect );
 | |
| 
 | |
| 		if (m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE )
 | |
| 			driver->draw2DRectangle(video::SColor(100,255,255,255), BRect);
 | |
| 
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	IGUIElement::draw();
 | |
| }
 | |
| 
 | |
| 
 | |
| void CGUIEditWorkspace::setDrawGrid(bool drawGrid)
 | |
| {
 | |
| 	DrawGrid = drawGrid;
 | |
| }
 | |
| 
 | |
| void CGUIEditWorkspace::setGridSize(const core::dimension2di& gridSize)
 | |
| {
 | |
| 	GridSize = gridSize;
 | |
| 	if (GridSize.Width < 2)
 | |
| 		GridSize.Width = 2;
 | |
| 	if (GridSize.Height < 2)
 | |
| 		GridSize.Height = 2;
 | |
| }
 | |
| 
 | |
| void CGUIEditWorkspace::setUseGrid(bool useGrid)
 | |
| {
 | |
| 	UseGrid = useGrid;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Removes a child.
 | |
| void CGUIEditWorkspace::removeChild(IGUIElement* child)
 | |
| {
 | |
| 	IGUIElement::removeChild(child);
 | |
| 
 | |
| 	// TODO: Can anyone find out why the workspace removes itself when it has no more children
 | |
| 	// and document it here?
 | |
| 	if (Children.empty())
 | |
| 		remove();
 | |
| }
 | |
| 
 | |
| void CGUIEditWorkspace::clearParentElements()
 | |
| {
 | |
| 	setSelectedElement(0);
 | |
| 	MouseOverElement = 0;
 | |
| 
 | |
| 	IGUIElement * el = Parent;
 | |
| 	grab();
 | |
| 
 | |
| 	if ( el->isMyChild(Environment->getFocus()) )
 | |
| 		Environment->setFocus(0);
 | |
| 
 | |
| 	while (!el->getChildren().empty())
 | |
| 	{
 | |
| 		el->removeChild(*(el->getChildren().begin()));
 | |
| 	}
 | |
| 
 | |
| 	el->addChild(this);
 | |
| 	drop();
 | |
| }
 | |
| 
 | |
| void CGUIEditWorkspace::updateAbsolutePosition()
 | |
| {
 | |
| 	core::rect<s32> parentRect(0,0,0,0);
 | |
| 
 | |
| 	if (Parent)
 | |
| 	{
 | |
| 		parentRect = Parent->getAbsolutePosition();
 | |
| 		RelativeRect.UpperLeftCorner.X = 0;
 | |
| 		RelativeRect.UpperLeftCorner.Y = 0;
 | |
| 		RelativeRect.LowerRightCorner.X = parentRect.getWidth();
 | |
| 		RelativeRect.LowerRightCorner.Y = parentRect.getHeight();
 | |
| 	}
 | |
| 
 | |
| 	IGUIElement::updateAbsolutePosition();
 | |
| }
 | |
| 
 | |
| void CGUIEditWorkspace::CopySelectedElementXML()
 | |
| {
 | |
| 	core::stringc XMLText;
 | |
| 	core::stringw wXMLText;
 | |
| 	// create memory write file
 | |
| 	io::CMemoryReadWriteFile* memWrite = new io::CMemoryReadWriteFile("#Clipboard#");
 | |
| 	// save gui to mem file
 | |
| 	io::IXMLWriter* xml = Environment->getFileSystem()->createXMLWriter(memWrite);
 | |
| 	Environment->writeGUIElement(xml, SelectedElement);
 | |
| 
 | |
| 	// copy to clipboard- wide chars not supported yet :(
 | |
| 	wXMLText = (wchar_t*)&memWrite->getData()[0];
 | |
| 	u32 i = memWrite->getData().size()/sizeof(wchar_t);
 | |
| 	if (wXMLText.size() > i)
 | |
| 		wXMLText[i] = L'\0';
 | |
| 	XMLText = wXMLText.c_str();
 | |
| 	memWrite->drop();
 | |
| 	xml->drop();
 | |
| 	Environment->getOSOperator()->copyToClipboard(XMLText.c_str());
 | |
| }
 | |
| 
 | |
| void CGUIEditWorkspace::PasteXMLToSelectedElement()
 | |
| {
 | |
| 	// get clipboard data
 | |
| 	const char * p = Environment->getOSOperator()->getTextFromClipboard();
 | |
| 	irr::core::stringw wXMLText;
 | |
| 	core::multibyteToWString(wXMLText, p);
 | |
| 
 | |
| 	io::CMemoryReadWriteFile* memWrite = new io::CMemoryReadWriteFile("#Clipboard#");
 | |
| 
 | |
| 	io::IXMLWriter* xmlw = Environment->getFileSystem()->createXMLWriter(memWrite);
 | |
| 	xmlw->writeXMLHeader(); // it needs one of those
 | |
| 	xmlw->drop();
 | |
| 
 | |
| 	// write clipboard data
 | |
| 	memWrite->write((void*)&wXMLText[0], wXMLText.size() * sizeof(wchar_t));
 | |
| 
 | |
| 	// rewind file
 | |
| 	memWrite->seek(0, false);
 | |
| 
 | |
| 	// read xml
 | |
| 	Environment->loadGUI(memWrite, SelectedElement);
 | |
| 
 | |
| 	// reset focus
 | |
| 	Environment->setFocus(this);
 | |
| 
 | |
| 	// drop the read file
 | |
| 	memWrite->drop();
 | |
| }
 | |
| 
 | |
| void CGUIEditWorkspace::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options)
 | |
| {
 | |
| 	out->addBool("DrawGrid", DrawGrid);
 | |
| 	out->addBool("UseGrid", UseGrid);
 | |
| 	out->addPosition2d("GridSize", core::position2di(GridSize.Width, GridSize.Height));
 | |
| 	out->addInt("MenuCommandStart", MenuCommandStart);
 | |
| }
 | |
| 
 | |
| void CGUIEditWorkspace::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
 | |
| {
 | |
| 	setDrawGrid(in->getAttributeAsBool("DrawGrid"));
 | |
| 	setUseGrid(in->getAttributeAsBool("UseGrid"));
 | |
| 
 | |
| 	core::position2di tmpp = in->getAttributeAsPosition2d("GridSize");
 | |
| 	core::dimension2di tmpd(tmpp.X, tmpp.Y);
 | |
| 	setGridSize(tmpd);
 | |
| 	setMenuCommandIDStart(in->getAttributeAsInt("MenuCommandStart"));
 | |
| }
 | |
| 
 | |
| 
 | |
| } // end namespace gui
 | |
| } // end namespace irr
 | |
| 
 | |
| 
 |