Procházet zdrojové kódy

Deleting entities will now affect all multiple selected entities, base Undo/Redo framework for editors

Ivan Safrin před 12 roky
rodič
revize
46ac6460d9

+ 26 - 3
IDE/Contents/Include/PolycodeEditor.h

@@ -27,8 +27,27 @@
 #include "PolycodeProject.h"
 #include "PolycodeClipboard.h"
 
+#define MAX_EDITOR_UNDO_ACTIONS	30
+
 using namespace Polycode;
 
+class PolycodeEditorActionData {
+	public:
+		PolycodeEditorActionData(){}
+		virtual ~PolycodeEditorActionData() {}
+};
+
+class PolycodeEditorAction  {
+	public:
+		PolycodeEditorAction(){}
+		~PolycodeEditorAction() {
+			delete beforeData;
+			delete afterData;
+		}
+		String actionName;
+		PolycodeEditorActionData *beforeData;
+		PolycodeEditorActionData *afterData;		
+};
 
 class PolycodeEditor : public ScreenEntity, public ClipboardProvider { 
 public:
@@ -40,10 +59,12 @@ public:
 	
 	virtual void handleEvent(Event *event);
 
-	virtual void Activate() {};
-	
+	virtual void Activate() {};	
 	virtual void saveFile(){};
 	
+	void didAction(String actionName, PolycodeEditorActionData *beforeData, PolycodeEditorActionData *afterData);
+	virtual void doAction(String actionName, PolycodeEditorActionData *data) {}
+	
 	virtual String Copy(void **data) { return ""; }
 	virtual void Paste(void *data, String clipboardType) {}
 
@@ -72,7 +93,9 @@ protected:
 	Vector2 editorSize;
 	
 	String editorType;
-	
+
+	std::vector<PolycodeEditorAction> editorActions;
+	int currentUndoPosition;
 };
 
 

+ 16 - 1
IDE/Contents/Include/PolycodeScreenEditor.h

@@ -49,6 +49,15 @@ class EntityBrowserData  {
 		Entity *entity;
 };
 
+class PolycodeScreenEditorActionData : PolycodeEditorActionData {
+	public:
+		PolycodeScreenEditorActionData() {}
+		PolycodeScreenEditorActionData(Vector3 vec3);
+		virtual ~PolycodeScreenEditorActionData(){}
+		
+		Vector3 vec3;
+};
+
 class EntityTreeView : public UIElement {
 	public:
 		EntityTreeView(Entity *rootEntity);
@@ -123,6 +132,8 @@ class PolycodeScreenEditorMain : public UIElement {
 		void resizePreviewScreen();		
 		void handleDroppedFile(OSFileEntry file, Number x, Number y);		
 		bool hasSelected(ScreenEntity *entity);
+		
+		void deleteEntity(ScreenEntity *entity);
 	
 		void applyEditorOnly(ScreenEntity *entity);
 		void applyEditorOnlyChildren(ScreenEntity *entity);
@@ -173,7 +184,7 @@ class PolycodeScreenEditorMain : public UIElement {
 		
 		ScreenEntity *layerBaseEntity;		
 						
-		ScreenEntity *selectedEntity;
+//		ScreenEntity *selectedEntity;
 		std::vector<ScreenEntity*> selectedEntities;		
 		
 		Transform2DSheet *transform2dSheet;
@@ -193,6 +204,8 @@ class PolycodeScreenEditorMain : public UIElement {
 		ScreenEntity *objectBaseEntity;		
 		ScreenEntity *placingPreviewEntity;												
 		bool multiSelect;
+		
+		PolycodeEditor *editor;		
 	protected:
 	
 		ScreenEntity *currentLayer;	
@@ -356,6 +369,8 @@ class PolycodeScreenEditor : public PolycodeEditor {
 		void saveCurveToObject(ObjectEntry *entry, BezierCurve *curve);
 		void saveEntityToObjectEntry(ScreenEntity *entity, ObjectEntry *entry);
 		void saveFile();
+		
+		void doAction(String actionName, PolycodeEditorActionData *data);
 					
 		void handleDroppedFile(OSFileEntry file, Number x, Number y);
 

+ 42 - 1
IDE/Contents/Source/PolycodeEditor.cpp

@@ -49,11 +49,15 @@ PolycodeEditor::PolycodeEditor(bool _isReadOnly) : ScreenEntity(), ClipboardProv
 	enableScissor = true;	
 	processInputEvents = true;
 	_hasChanges = false;
-
+	
+	currentUndoPosition = 0;
+	
 	Core *core = CoreServices::getInstance()->getCore();
 	
 	core->addEventListener(this, Core::EVENT_COPY);
 	core->addEventListener(this, Core::EVENT_PASTE);
+	core->addEventListener(this, Core::EVENT_UNDO);	
+	core->addEventListener(this, Core::EVENT_REDO);	
 }
 
 void PolycodeEditor::setHasChanges(bool newVal) {
@@ -86,10 +90,47 @@ void PolycodeEditor::handleEvent(Event *event) {
 				}
 			}
 			break;
+			case Core::EVENT_UNDO:
+			{
+				if(editorActions.size() > 0) {
+				doAction(editorActions[currentUndoPosition].actionName, editorActions[currentUndoPosition].beforeData);
+				currentUndoPosition--;
+				if(currentUndoPosition < 0) {
+					currentUndoPosition = 0;
+				}
+				}				
+			}
+			break;
+			case Core::EVENT_REDO:
+			{
+				if(editorActions.size() > 0) {			
+				currentUndoPosition++;
+				if(currentUndoPosition > editorActions.size()-1) {
+					currentUndoPosition = editorActions.size()-1;
+				} else {
+					doAction(editorActions[currentUndoPosition].actionName, editorActions[currentUndoPosition].afterData);
+				}
+				}
+			}
+			break;			
 		}
 	}
 }
 
+void PolycodeEditor::didAction(String actionName, PolycodeEditorActionData *beforeData, PolycodeEditorActionData *afterData) {
+	PolycodeEditorAction newAction;
+	newAction.actionName = actionName;
+	newAction.beforeData = beforeData;
+	newAction.afterData = afterData;	
+	editorActions.push_back(newAction);
+	
+	if(editorActions.size() > MAX_EDITOR_UNDO_ACTIONS) {
+		editorActions.erase(editorActions.begin());
+	}
+	
+	currentUndoPosition = editorActions.size()-1;	
+}
+
 void PolycodeEditor::Resize(int x, int y) {
 	editorSize = Vector2(x,y);
 	Vector2 pos = getScreenPosition();

+ 111 - 79
IDE/Contents/Source/PolycodeScreenEditor.cpp

@@ -27,6 +27,9 @@ extern UIColorPicker *globalColorPicker;
 extern PolycodeFrame *globalFrame;
 extern UIGlobalMenu *globalMenu;
 
+PolycodeScreenEditorActionData::PolycodeScreenEditorActionData(Vector3 vec3) {
+	this->vec3 = vec3;
+}
 
 ScreenEntityNameDisplay::ScreenEntityNameDisplay(ScreenEntity *targetEntity) : ScreenEntity() {
 	label = new ScreenLabel(targetEntity->id, 10, "mono");
@@ -281,9 +284,7 @@ PolycodeScreenEditorMain::PolycodeScreenEditorMain() {
 	int fontSize = conf->getNumericValue("Polycode", "uiDefaultFontSize");	
 	Number padding = conf->getNumericValue("Polycode", "uiWindowSkinPadding");	
 
-	isScalingEntity = false;
-	
-	selectedEntity = NULL;
+	isScalingEntity = false;	
 	isDraggingEntity = false; 
 		
 	baseEntity = new ScreenEntity();
@@ -820,9 +821,11 @@ void PolycodeScreenEditorMain::syncTransformToSelected() {
 	sizePreviewShape->setShapeSize(layerBaseEntity->getWidth() * objectBaseEntity->getScale().x, layerBaseEntity->getHeight() * objectBaseEntity->getScale().x);
 
 
-	if(!selectedEntity)
+	if(selectedEntities.size() == 0)
 		return;
 	
+	ScreenEntity *selectedEntity = selectedEntities[0];
+	
 	objectBaseEntity->rebuildTransformMatrix();	
 	selectedEntity->rebuildTransformMatrix();
 	
@@ -993,6 +996,15 @@ void PolycodeScreenEditorMain::handleMouseUp(Vector2 position) {
 		break;
 		case MODE_SELECT:	
 		{
+		/*
+			if(moving) {
+				editor->didAction("move", NULL, NULL);
+			} else if(scalingX || scalingY) {
+				editor->didAction("scale", NULL, NULL);	
+			} else if(rotating) {
+				editor->didAction("rotate", NULL, NULL);				
+			}
+			*/
 			moving = false;
 			scalingY = false;
 			scalingX = false;
@@ -1110,8 +1122,8 @@ void PolycodeScreenEditorMain::handleMouseMove(Vector2 position) {
 								
 				for(int i=0; i < selectedEntities.size(); i++) {			
 				
-					Number baseDist = mouseBase.distance(selectedEntities[i]->getScreenPosition());
-					Number newDist = newMousePosition.distance(selectedEntities[i]->getScreenPosition());
+					Number baseDist = mouseBase.distance(screenTransformShape->getScreenPosition());
+					Number newDist = newMousePosition.distance(screenTransformShape->getScreenPosition());
 																					
 					Number scaleMod = 0.04;
 					
@@ -1591,7 +1603,7 @@ void PolycodeScreenEditorMain::selectEntity(ScreenEntity *entity) {
 	screenEntitySheet->entity = NULL;
 				
 	if(!entity) {
-		selectedEntity = NULL;
+		selectedEntities.clear();
 		screenTransform->visible = false;
 		screenTransform->enabled = false;
 		screenTransformShape->visible = false;			
@@ -1674,7 +1686,6 @@ void PolycodeScreenEditorMain::selectEntity(ScreenEntity *entity) {
 		screenTransformShape->visible = false;	
 	}
 	
-	selectedEntity = entity;
 	syncTransformToSelected();	
 		
 	entityProps->updateProps();	
@@ -1711,6 +1722,35 @@ void PolycodeScreenEditorMain::setEntityRefVisibility(ScreenEntity *entity, bool
 	}
 }
 
+void PolycodeScreenEditorMain::deleteEntity(ScreenEntity *entity) {				
+	if(entity == layerBaseEntity) {
+		PolycodeConsole::print("You cannot delete the root entity.\n");
+	} else if(entity->getEntityProp("editor_type") == "layer" && layers.size() == 1) {
+		PolycodeConsole::print("You cannot delete the last layer.\n");						
+	} else {
+		entity->ownsChildren = true;
+		entity->getParentEntity()->removeChild(entity);
+
+		if(entity->getEntityProp("editor_type") == "layer") {
+			for(int i=0; i < layers.size(); i++) {
+				if(layers[i] == entity) {
+					layers.erase(layers.begin()+i);
+				}
+			}
+		}
+							
+
+		if(entity == currentLayer) {
+				setCurrentLayer(NULL);
+				setCurrentLayer(layers[0]);
+				treeView->targetLayer = currentLayer;
+		}
+							
+		delete entity;					
+		treeView->Refresh();
+	}
+}
+
 void PolycodeScreenEditorMain::handleEvent(Event *event) {
 	InputEvent *inputEvent = (InputEvent*) event;
 	
@@ -1789,7 +1829,7 @@ void PolycodeScreenEditorMain::handleEvent(Event *event) {
 		if(event->getEventCode() == InputEvent::EVENT_KEYDOWN) {
 			switch(inputEvent->key) {
 				case Polycode::KEY_ESCAPE:
-					if(selectedEntity) {
+					if(selectedEntities.size() > 0) {
 						scalingY = false;
 						scalingX = false;
 						moving = false;
@@ -1799,34 +1839,11 @@ void PolycodeScreenEditorMain::handleEvent(Event *event) {
 				break;
 				case Polycode::KEY_BACKSPACE:
 				{
-					if(selectedEntity) {					
-						if(selectedEntity->hasFocus) {					
-						if(selectedEntity == layerBaseEntity) {
-							PolycodeConsole::print("You cannot delete the root entity.\n");
-						} else if(selectedEntity->getEntityProp("editor_type") == "layer" && layers.size() == 1) {
-							PolycodeConsole::print("You cannot delete the last layer.\n");						
-						} else {
-							selectedEntity->ownsChildren = true;
-							selectedEntity->getParentEntity()->removeChild(selectedEntity);
-					
-							if(selectedEntity->getEntityProp("editor_type") == "layer") {
-								for(int i=0; i < layers.size(); i++) {
-									if(layers[i] == selectedEntity) {
-										layers.erase(layers.begin()+i);
-									}
-								}
-							}
-							
-							if(selectedEntity == currentLayer) {
-								setCurrentLayer(NULL);
-								setCurrentLayer(layers[0]);
-								treeView->targetLayer = currentLayer;
-							}							
-							delete selectedEntity;
-							selectEntity(NULL);							
-							treeView->Refresh();
-						}
+					if(selectedEntities.size() > 0) {
+						for(int i=0; i < selectedEntities.size(); i++) {
+							deleteEntity(selectedEntities[i]);
 						}
+						selectEntity(NULL);
 					}
 				}
 				break;
@@ -1868,20 +1885,20 @@ void PolycodeScreenEditorMain::handleEvent(Event *event) {
 	}
 
 	if(event->getDispatcher() == transformScalerXY) {
-		if(selectedEntity) {
+		if(selectedEntities.size() > 0) {
 			scalingY = true;
 			scalingX = true;			
 			resetSelectedEntityTransforms();
 			mouseBase = CoreServices::getInstance()->getCore()->getInput()->getMousePosition();			
 		}	
 	} else if(event->getDispatcher() == transformScalerY) {
-		if(selectedEntity) {
+		if(selectedEntities.size() > 0) {
 			scalingY = true;
 			resetSelectedEntityTransforms();
 			mouseBase = CoreServices::getInstance()->getCore()->getInput()->getMousePosition();			
 		}
 	} else if(event->getDispatcher() == transformScalerX) {
-		if(selectedEntity) {
+		if(selectedEntities.size() > 0) {
 			scalingX = true;
 			resetSelectedEntityTransforms();
 			mouseBase = CoreServices::getInstance()->getCore()->getInput()->getMousePosition();			
@@ -1889,7 +1906,7 @@ void PolycodeScreenEditorMain::handleEvent(Event *event) {
 	}
 	
 	if(event->getDispatcher() == transformRotator) {
-		if(selectedEntity) {
+		if(selectedEntities.size() > 0) {
 			rotating = true;
 			resetSelectedEntityTransforms();
 			mouseBase = CoreServices::getInstance()->getCore()->getInput()->getMousePosition();
@@ -1904,56 +1921,55 @@ void PolycodeScreenEditorMain::handleEvent(Event *event) {
 	if(event->getEventCode() == UIEvent::CLICK_EVENT && event->getEventType() == "UIEvent") {
 	
 		if(event->getDispatcher() == moveUpButton) {
-			if(selectedEntity) {
-				if(selectedEntity->getParentEntity()) {
-					for(int i=0; i < selectedEntities.size(); i++) {
-						((ScreenEntity*)selectedEntities[i]->getParentEntity())->moveChildUp(selectedEntities[i]);
-					}
-
+			for(int i=0; i < selectedEntities.size(); i++) {
+				if(selectedEntities[i]->getParentEntity()) {
+					((ScreenEntity*)selectedEntities[i]->getParentEntity())->moveChildUp(selectedEntities[i]);
 				}
-			}	
+			}
 		}
 
 		if(event->getDispatcher() == moveDownButton) {
-			if(selectedEntity) {
-				if(selectedEntity->getParentEntity()) {
-					for(int i=0; i < selectedEntities.size(); i++) {
-						((ScreenEntity*)selectedEntities[i]->getParentEntity())->moveChildDown(selectedEntities[i]);
-					}
+			for(int i=0; i < selectedEntities.size(); i++) {
+				if(selectedEntities[i]->getParentEntity()) {
+					((ScreenEntity*)selectedEntities[i]->getParentEntity())->moveChildDown(selectedEntities[i]);
+				}
+			}
+		}
 
+		if(event->getDispatcher() == moveTopButton) {
+			for(int i=0; i < selectedEntities.size(); i++) {
+				if(selectedEntities[i]->getParentEntity()) {
+					((ScreenEntity*)selectedEntities[i]->getParentEntity())->moveChildTop(selectedEntities[i]);
 				}
-			}	
+			}
 		}
 
 		if(event->getDispatcher() == moveTopButton) {
-			if(selectedEntity) {
-				if(selectedEntity->getParentEntity()) {
-					for(int i=0; i < selectedEntities.size(); i++) {
-						((ScreenEntity*)selectedEntities[i]->getParentEntity())->moveChildTop(selectedEntities[i]);
-					}
+			for(int i=0; i < selectedEntities.size(); i++) {
+				if(selectedEntities[i]->getParentEntity()) {
+					((ScreenEntity*)selectedEntities[i]->getParentEntity())->moveChildTop(selectedEntities[i]);
 				}
-			}	
+			}
 		}
 
 		if(event->getDispatcher() == moveBottomButton) {
-			if(selectedEntity) {
-				if(selectedEntity->getParentEntity()) {
-					for(int i=0; i < selectedEntities.size(); i++) {
-						((ScreenEntity*)selectedEntities[i]->getParentEntity())->moveChildBottom(selectedEntities[i]);
-					}
+			for(int i=0; i < selectedEntities.size(); i++) {
+				if(selectedEntities[i]->getParentEntity()) {
+					((ScreenEntity*)selectedEntities[i]->getParentEntity())->moveChildBottom(selectedEntities[i]);
 				}
-			}	
+			}
 		}
-		
+
 		if(event->getDispatcher() == unparentButton) {
-			if(selectedEntity) {
-				if(selectedEntity->getParentEntity()) {
-					selectedEntity->getParentEntity()->removeChild(selectedEntity);
-					currentLayer->addChild(selectedEntity);
-					syncTransformToSelected();
+			for(int i=0; i < selectedEntities.size(); i++) {
+				if(selectedEntities[i]->getParentEntity()) {
+					selectedEntities[i]->getParentEntity()->removeChild(selectedEntities[i]);
+					currentLayer->addChild(selectedEntities[i]);
 				}
-			}	
-		}			
+			}
+			syncTransformToSelected();			
+		}
+			
 	
 		if(event->getDispatcher() == arrowToolButton) {
 			selectorImage->setPosition(arrowToolButton->getPosition().x - 4, arrowToolButton->getPosition().y - 4);
@@ -2088,7 +2104,7 @@ void PolycodeScreenEditorMain::processEventForEntity(ScreenEntity *childEntity,
 			if(inputEvent->getEventCode() == InputEvent::EVENT_MOUSEDOWN) {
 				if(mode == MODE_SELECT) {
 					selectEntity(childEntity);
-					if(selectedEntity) {
+					if(selectedEntities.size() > 0) {
 						moving = true;
 						mouseBase = CoreServices::getInstance()->getCore()->getInput()->getMousePosition();
 					}					
@@ -2249,6 +2265,7 @@ PolycodeScreenEditor::PolycodeScreenEditor() : PolycodeEditor(true){
 	addChild(mainSizer);	
 
 	editorMain = new PolycodeScreenEditorMain();
+	editorMain->editor = this;
 	editorMain->addEventListener(this, Event::CHANGE_EVENT);
 	mainSizer->addLeftChild(editorMain);
 	
@@ -2307,9 +2324,16 @@ void PolycodeScreenEditorMain::Paste(void *data, String clipboardType) {
 				ScreenEntity *entity = (ScreenEntity*) newData->entities[i]->Clone(true, true);
 				entity->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
 				entity->addEventListener(this, InputEvent::EVENT_MOUSEUP);
-				if(selectedEntity && selectedEntity != currentLayer) {
-					selectedEntity->getParentEntity()->addChild(entity);
-				} else {
+				
+				bool addToLayer = true;
+				if(selectedEntities.size() > 0) {
+					if(selectedEntities[0] != currentLayer) {
+						selectedEntities[0]->getParentEntity()->addChild(entity);
+						addToLayer = false;
+					}
+				}
+				
+				if(addToLayer) {
 					currentLayer->addChild(entity);
 				}
 				applyEditorProperties(entity);
@@ -2337,6 +2361,10 @@ void PolycodeScreenEditor::Activate() {
 	editorMain->labelSheet->refreshFonts();
 }
 
+void PolycodeScreenEditor::doAction(String actionName, PolycodeEditorActionData *data) {
+	printf("DOING ACTION: %s\n", actionName.c_str());
+}
+
 void PolycodeScreenEditor::saveCurveToObject(ObjectEntry *entry, BezierCurve *curve) {
 	ObjectEntry *controlPoints = entry->addChild("controlPoints");
 	
@@ -2564,8 +2592,12 @@ void PolycodeScreenEditor::handleEvent(Event *event) {
 			editorMain->selectEntity((ScreenEntity*)treeView->selectedEntity);
 		}
 
-		if(event->getDispatcher() == editorMain) {			
-			treeView->selectedEntity = editorMain->selectedEntity;
+		if(event->getDispatcher() == editorMain) {
+			if(editorMain->selectedEntities.size() > 0) {
+				treeView->selectedEntity = editorMain->selectedEntities[0];			
+			} else {
+				treeView->selectedEntity = NULL;
+			}			
 		}
 
 	}