Просмотр исходного кода

Hooked up IDE property controls to the Undo/Redo system and implemented Undo/Redo in the screen editor for most actions. ColorPicker and HSlide no longer send out change events on drag, only on release, multiple fixes in the IDE

Ivan Safrin 12 лет назад
Родитель
Сommit
d857b25e22

+ 127 - 12
IDE/Contents/Include/PolycodeProps.h

@@ -26,18 +26,26 @@
 #include "PolycodeUI.h"
 #include "Polycode.h"
 #include "OSBasics.h"
+#include "PolycodeEditor.h"
 
 using namespace Polycode;
 
 
+class PolycodeEditorPropActionData;
+
 class PropProp : public UIElement {
 	public:
 		PropProp(String caption, String type);
 		~PropProp();
-	
+
+		virtual void setPropData(PolycodeEditorPropActionData* data) {}
+		
 		String propType;
 		ScreenLabel *label;
-		ScreenEntity *propContents;
+		ScreenEntity *propContents;				
+		
+		bool suppressChangeEvent;		
+		bool settingFromData;
 };
 
 class Vector2Prop : public PropProp {
@@ -47,9 +55,14 @@ class Vector2Prop : public PropProp {
 		void handleEvent(Event *event);
 		void set(Vector2 position);
 		Vector2 get();
+		
+		void setPropData(PolycodeEditorPropActionData* data);
 				
 		UITextInput *positionX;
-		UITextInput *positionY;						
+		UITextInput *positionY;	
+		
+		Vector2 lastData;
+		Vector2 currentData;		
 };
 
 class SliderProp : public PropProp {
@@ -59,9 +72,14 @@ class SliderProp : public PropProp {
 		void handleEvent(Event *event);
 		void set(Number number);
 		Number get();
+		
+		void setPropData(PolycodeEditorPropActionData* data);		
 				
 		UIHSlider *slider;
 		ScreenLabel *valueLabel;
+		
+		Number lastValue;
+		Number currentValue;
 };
 
 
@@ -72,8 +90,13 @@ class NumberProp : public PropProp {
 		void handleEvent(Event *event);
 		void set(Number number);
 		Number get();
+		
+		void setPropData(PolycodeEditorPropActionData* data);
 				
 		UITextInput *numberEntry;
+		
+		Number lastValue;
+		Number currentValue;
 };
 
 
@@ -98,8 +121,13 @@ class StringProp : public PropProp {
 		void handleEvent(Event *event);
 		void set(String str);
 		String get();
+
+		void setPropData(PolycodeEditorPropActionData* data);
 				
 		UITextInput *stringEntry;
+		
+		String lastValue;
+		String currentValue;
 };
 
 class ColorProp : public PropProp {
@@ -108,8 +136,13 @@ class ColorProp : public PropProp {
 		~ColorProp();		
 		void handleEvent(Event *event);
 		
+		virtual void setPropData(PolycodeEditorPropActionData* data);
+		
 		void set(Color color);
 		Color get();
+		
+		Color currentColor;
+		Color lastColor;
 				
 		UIColorBox *colorEntry;
 };
@@ -120,10 +153,15 @@ class ComboProp : public PropProp {
 		~ComboProp();		
 		void handleEvent(Event *event);
 		
+		void setPropData(PolycodeEditorPropActionData* data);
+			
 		void set(unsigned int index);
 		unsigned int get();
 				
 		UIComboBox *comboEntry;
+		
+		int lastValue;
+		int currentValue;
 };
 
 class BoolProp : public PropProp {
@@ -132,10 +170,15 @@ class BoolProp : public PropProp {
 		~BoolProp();		
 		void handleEvent(Event *event);
 		
+		void setPropData(PolycodeEditorPropActionData* data);
+		
 		void set(bool val);
 		bool get();
 				
 		UICheckBox *checkEntry;
+		
+		bool lastData;
+		bool currentData;
 };
 
 class SoundProp : public PropProp {
@@ -147,10 +190,15 @@ class SoundProp : public PropProp {
 		void set(String soundPath);
 		String get();
 		
+		void setPropData(PolycodeEditorPropActionData* data);
+		
 		Sound *previewSound;
 		ScreenLabel *soundFile;		
 		UIButton *changeButton;
-		UIButton *playButton;		
+		UIButton *playButton;	
+		
+		String lastData;
+		String currentData;
 };
 
 class BezierRGBACurveProp : public PropProp {
@@ -187,23 +235,33 @@ class TextureProp : public PropProp {
 		
 		void set(Texture *texture);
 		Texture* get();
+		
+		void setPropData(PolycodeEditorPropActionData* data);
 				
 		ScreenShape *previewShape;
 		UIButton *changeButton;
 		ScreenLabel *textureLabel;
+		
+		String lastData;
+		String currentData;
 };
 
 class ScreenSpriteProp : public PropProp {
 	public:
 		ScreenSpriteProp(String caption);
 		~ScreenSpriteProp();
-		void handleEvent(Event *event);			
+		void handleEvent(Event *event);
+		
+		void setPropData(PolycodeEditorPropActionData* data);
 		
 		void set(String fileName);
 		String get();		
 				
 		ScreenSprite *previewSprite;
 		UIButton *changeButton;
+		
+		String lastData;
+		String currentData;
 };
 
 
@@ -213,20 +271,27 @@ class ScreenEntityInstanceProp : public PropProp {
 		~ScreenEntityInstanceProp();
 		void handleEvent(Event *event);			
 		
+		void setPropData(PolycodeEditorPropActionData* data);
+		
 		void set(String fileName);
 		String get();		
 				
 		ScreenEntityInstance *previewInstance;
 		UIButton *changeButton;
+		
+		String lastData;
+		String currentData;
+		
 };
 
-
 class PropSheet : public UIElement {
 	public:
 		PropSheet(String caption, String type);
 		~PropSheet();		
 		void Resize(Number width, Number height);
 		
+		virtual void applyPropActionData(PolycodeEditorPropActionData *data);
+		
 		void handleEvent(Event *event);
 		
 		void setCollapsed(bool val);
@@ -292,8 +357,8 @@ class ShaderTexturesSheet : public PropSheet {
 class EntitySheet : public PropSheet {
 	public:
 		EntitySheet();
-		~EntitySheet();
-		
+		~EntitySheet();	
+	
 		void handleEvent(Event *event);
 		void Update();
 				
@@ -312,7 +377,9 @@ class EntityPropSheet : public PropSheet {
 		void handleEvent(Event *event);
 		void Update();
 		void refreshProps();
-				
+
+		void applyPropActionData(PolycodeEditorPropActionData *data);
+
 		UIButton *addButton;
 		
 		Entity *entity;
@@ -320,7 +387,7 @@ class EntityPropSheet : public PropSheet {
 		
 		int lastNumProps;
 		
-		int removeIndex;
+		int removeIndex;		
 		
 };
 
@@ -357,7 +424,8 @@ class ScreenLabelSheet : public PropSheet {
 		void handleEvent(Event *event);
 		void Update();
 				
-		ScreenLabel *label;	
+		ScreenLabel *label;
+		ScreenLabel *lastLabel;	
 		
 		int lastSize;
 		String lastFont;
@@ -544,4 +612,51 @@ class PropList : public UIElement {
 		std::vector<PropSheet*> props;	
 		ScreenShape *bg;
 		ScreenShape *bg2;				
-};
+};
+
+class PolycodeEditorPropActionData : public PolycodeEditorActionData {
+	public:
+		PolycodeEditorPropActionData(){}
+		virtual ~PolycodeEditorPropActionData(){}
+		
+		bool boolVal;
+		String stringVal;
+		int intVal;
+		Number numVal;
+		Color colorVal;
+		Vector3 vector3Val;
+		Vector2 vector2Val;
+		
+		Entity entity;
+		
+		PropSheet *sheet;
+		PropProp *prop;
+};
+
+
+PolycodeEditorPropActionData *PropDataBool(bool val);
+PolycodeEditorPropActionData *PropDataInt(int val);
+PolycodeEditorPropActionData *PropDataNumber(Number val);
+PolycodeEditorPropActionData *PropDataString(String val);
+PolycodeEditorPropActionData *PropDataColor(Color val);
+PolycodeEditorPropActionData *PropDataVector3(Vector3 val);
+PolycodeEditorPropActionData *PropDataVector2(Vector2 val);
+PolycodeEditorPropActionData *PropDataEntity(Entity *entity);
+
+class PropEvent : public Event {
+	public:
+		PropEvent(PropProp *prop, PropSheet *sheet, PolycodeEditorPropActionData *beforeData, PolycodeEditorPropActionData *afterData);
+		virtual ~PropEvent();
+		
+		void setSheet(PropSheet *sheet);
+		
+		PropProp *prop;
+		PropSheet *sheet;
+		
+		PolycodeEditorPropActionData *beforeData;
+		PolycodeEditorPropActionData *afterData;
+				
+		static const int EVENTBASE_PROPEVENT = 0xC00;
+		static const int EVENT_PROP_CHANGE = EVENTBASE_PROPEVENT+0;
+
+};

+ 2 - 0
IDE/Contents/Source/PolycodeEditor.cpp

@@ -118,6 +118,8 @@ void PolycodeEditor::handleEvent(Event *event) {
 }
 
 void PolycodeEditor::didAction(String actionName, PolycodeEditorActionData *beforeData, PolycodeEditorActionData *afterData, bool setFileChanged) {
+
+//	printf("DID ACTION: %s\n", actionName.c_str());
 	
 	if(setFileChanged) {
 		setHasChanges(true);

+ 324 - 87
IDE/Contents/Source/PolycodeProps.cpp

@@ -27,6 +27,91 @@ extern UIColorPicker *globalColorPicker;
 extern PolycodeFrame *globalFrame;
 extern UIGlobalMenu *globalMenu;
 
+PolycodeEditorPropActionData *PropDataBool(bool val) {
+	PolycodeEditorPropActionData *data = new PolycodeEditorPropActionData();
+	data->boolVal = val;
+	return data;
+}
+
+PolycodeEditorPropActionData *PropDataInt(int val) {
+	PolycodeEditorPropActionData *data = new PolycodeEditorPropActionData();
+	data->intVal = val;
+	return data;
+}
+
+PolycodeEditorPropActionData *PropDataNumber(Number val) {
+	PolycodeEditorPropActionData *data = new PolycodeEditorPropActionData();
+	data->numVal = val;
+	return data;
+}
+
+PolycodeEditorPropActionData *PropDataString(String val) {
+	PolycodeEditorPropActionData *data = new PolycodeEditorPropActionData();
+	data->stringVal = val;
+	return data;
+}
+
+PolycodeEditorPropActionData *PropDataColor(Color val) {
+	PolycodeEditorPropActionData *data = new PolycodeEditorPropActionData();
+	data->colorVal = val;
+	return data;
+}
+
+PolycodeEditorPropActionData *PropDataVector3(Vector3 val) {
+	PolycodeEditorPropActionData *data = new PolycodeEditorPropActionData();
+	data->vector3Val = val;
+	return data;
+}
+
+PolycodeEditorPropActionData *PropDataVector2(Vector2 val) {
+	PolycodeEditorPropActionData *data = new PolycodeEditorPropActionData();
+	data->vector2Val = val;
+	return data;
+}
+
+PolycodeEditorPropActionData *PropDataEntity(Entity *entity) {
+	PolycodeEditorPropActionData *data = new PolycodeEditorPropActionData();
+	data->entity = *entity;
+	data->entity.ownsChildren = false;
+	for(int i=0; i < data->entity.getNumChildren(); i++) {
+		data->entity.removeChild(data->entity.getChildAtIndex(i));
+	}
+	return data;
+}
+
+PropEvent::PropEvent(PropProp *prop, PropSheet *sheet, PolycodeEditorPropActionData *beforeData, PolycodeEditorPropActionData *afterData) : Event() {
+	this->prop = prop;
+	this->sheet = sheet;
+	this->beforeData = beforeData;
+	this->afterData = afterData;	
+	this->eventType = "PropEvent";
+	
+	if(this->beforeData) {
+		this->beforeData->sheet = sheet;
+		this->beforeData->prop = prop;
+	}
+
+	if(this->afterData) {
+		this->afterData->sheet = sheet;
+		this->afterData->prop = prop;
+	}
+		
+}
+
+void PropEvent::setSheet(PropSheet *sheet) {
+	if(this->beforeData) {
+		this->beforeData->sheet = sheet;
+	}
+
+	if(this->afterData) {
+		this->afterData->sheet = sheet;
+	}
+}
+
+PropEvent::~PropEvent() {
+
+}
+
 PropList::PropList(String caption) : UIElement() {
 
 	setPositionMode(ScreenEntity::POSITION_TOPLEFT);
@@ -106,7 +191,9 @@ void PropList::Resize(Number width, Number height) {
 void PropList::handleEvent(Event *event) {
 	if(event->getEventType() == "" && event->getEventCode() == Event::COMPLETE_EVENT) {
 		Resize(width, height);
-	}	
+	} else if(event->getEventCode() == Event::CHANGE_EVENT) {
+	
+	}
 }
 
 void PropList::addPropSheet(PropSheet *sheet) {
@@ -114,6 +201,7 @@ void PropList::addPropSheet(PropSheet *sheet) {
 	props.push_back(sheet);
 	Resize(width, height);
 	sheet->addEventListener(this, Event::COMPLETE_EVENT);
+	sheet->addEventListener(this, Event::CHANGE_EVENT);	
 }
 
 PropSheet::PropSheet(String caption, String type) : UIElement() {
@@ -177,8 +265,13 @@ void PropSheet::handleEvent(Event *event) {
 		if(event->getDispatcher() == expandButton) {
 			setCollapsed(false);
 		}
-
 	}
+	
+	if(event->getEventCode() == PropEvent::EVENT_PROP_CHANGE ) {
+		PropEvent *propEvent = (PropEvent*) event;
+		PropEvent *newEvent = new PropEvent(propEvent->prop, this, propEvent->beforeData, propEvent->afterData);		
+		dispatchEvent(newEvent, PropEvent::EVENT_PROP_CHANGE);
+	}	
 }
 
 PropSheet::~PropSheet() {
@@ -203,11 +296,19 @@ void PropSheet::addProp(PropProp *prop) {
 	contents->addChild(prop);
 	props.push_back(prop);
 	prop->addEventListener(this, Event::CHANGE_EVENT);
+	prop->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);	
 	Resize(width, height);
 }
 
+
+void PropSheet::applyPropActionData(PolycodeEditorPropActionData *data) {
+	data->prop->setPropData(data);
+}
+
+
 PropProp::PropProp(String caption, String type) : UIElement() {
 
+	suppressChangeEvent = false;
 	propType = type;
 	label = new ScreenLabel(caption, 12);
 	label->color.a = 0.4;
@@ -237,6 +338,9 @@ Vector2Prop::Vector2Prop(String caption) : PropProp(caption, "Vector2") {
 	label->color.a = 0.4;
 	propContents->addChild(label);
 	label->setPosition(60, 6);	
+	
+	positionX = NULL;
+	positionY = NULL;
 
 	positionX = new UITextInput(false, 50, 12);
 	positionX->addEventListener(this, UIEvent::CHANGE_EVENT);
@@ -258,15 +362,31 @@ Vector2Prop::Vector2Prop(String caption) : PropProp(caption, "Vector2") {
 
 void Vector2Prop::handleEvent(Event *event) {
 	if(event->getDispatcher() == positionX || event->getDispatcher() == positionY) {
-		if(event->getEventType() == "UIEvent" && event->getEventCode() == UIEvent::CHANGE_EVENT) {		
-			dispatchEvent(new Event(), Event::CHANGE_EVENT);
+		if(event->getEventType() == "UIEvent" && event->getEventCode() == UIEvent::CHANGE_EVENT) {
+		
+			if(positionX && positionY) {
+				lastData = currentData;
+				currentData = Vector2(atof(positionX->getText().c_str()), atof(positionY->getText().c_str()));
+			}
+			if(!suppressChangeEvent) {
+				dispatchEvent(new Event(), Event::CHANGE_EVENT);
+				dispatchEvent(new PropEvent(this, NULL, PropDataVector2(lastData), PropDataVector2(currentData)), PropEvent::EVENT_PROP_CHANGE);
+
+			}
 		}
 	}
 }
 
+void Vector2Prop::setPropData(PolycodeEditorPropActionData* data) {
+	set(data->vector2Val);
+	dispatchEvent(new Event(), Event::CHANGE_EVENT);
+}
+
 void Vector2Prop::set(Vector2 position) {
+	suppressChangeEvent = true;
 	positionX->setText(String::NumberToString(position.x));
 	positionY->setText(String::NumberToString(position.y));
+	suppressChangeEvent = false;	
 }
 
 Vector2 Vector2Prop::get() {
@@ -300,7 +420,12 @@ CustomProp::CustomProp(String key, String value) : PropProp("", "Custom") {
 }
 
 CustomProp::~CustomProp() {
-
+	keyEntry->removeAllHandlersForListener(this);
+	valueEntry->removeAllHandlersForListener(this);
+	removeButton->removeAllHandlersForListener(this);
+	delete removeButton;
+	delete keyEntry;
+	delete valueEntry;
 }
 
 void CustomProp::handleEvent(Event *event) {
@@ -343,17 +468,29 @@ StringProp::StringProp(String caption) : PropProp(caption, "String") {
 void StringProp::handleEvent(Event *event) {
 	if(event->getDispatcher() == stringEntry) {
 		if(event->getEventType() == "UIEvent" && event->getEventCode() == UIEvent::CHANGE_EVENT) {		
-			dispatchEvent(new Event(), Event::CHANGE_EVENT);
+			lastValue = currentValue;
+			currentValue = stringEntry->getText();
+			if(!suppressChangeEvent) {
+				dispatchEvent(new Event(), Event::CHANGE_EVENT);
+				dispatchEvent(new PropEvent(this, NULL, PropDataString(lastValue), PropDataString(currentValue)), PropEvent::EVENT_PROP_CHANGE);
+			}
 		}
 	}
 }
 
+void StringProp::setPropData(PolycodeEditorPropActionData* data) {
+	set(data->stringVal);
+	dispatchEvent(new Event(), Event::CHANGE_EVENT);	
+}
+
 void StringProp::set(String str) {
-	stringEntry->setText(str);
+	suppressChangeEvent = true;
+	stringEntry->setText(str, false);
+	suppressChangeEvent = false;	
 }
 
 String StringProp::get() {
-	return stringEntry->getText();
+	return currentValue;
 }
 	
 		
@@ -362,7 +499,7 @@ StringProp::~StringProp() {
 }
 
 SliderProp::SliderProp(String caption, Number min, Number max) : PropProp(caption, "Slider") {
-
+	
 	slider = new UIHSlider(min, max, 100);
 	slider->addEventListener(this, UIEvent::CHANGE_EVENT);
 	slider->setPosition(5, 8);
@@ -380,19 +517,35 @@ SliderProp::SliderProp(String caption, Number min, Number max) : PropProp(captio
 void SliderProp::handleEvent(Event *event) {
 	if(event->getDispatcher() == slider) {
 		if(event->getEventType() == "UIEvent" && event->getEventCode() == UIEvent::CHANGE_EVENT) {		
-			dispatchEvent(new Event(), Event::CHANGE_EVENT);
+			lastValue = currentValue;
+			currentValue = slider->getSliderValue();		
+			if(!suppressChangeEvent) {
+				dispatchEvent(new Event(), Event::CHANGE_EVENT);
+				dispatchEvent(new PropEvent(this, NULL, PropDataNumber(lastValue), PropDataNumber(currentValue)), PropEvent::EVENT_PROP_CHANGE);
+			}
 			valueLabel->setText(String::NumberToString(slider->getSliderValue()));
 		}
 	}
 }
 
+void SliderProp::setPropData(PolycodeEditorPropActionData* data) {
+	set(data->numVal);
+	lastValue = currentValue;
+	currentValue = slider->getSliderValue();			
+	dispatchEvent(new Event(), Event::CHANGE_EVENT);	
+}
+
 void SliderProp::set(Number number) {
+	suppressChangeEvent = true;
 	slider->setSliderValue(number);
+	lastValue = currentValue;
+	currentValue = slider->getSliderValue();	
 	valueLabel->setText(String::NumberToString(slider->getSliderValue()));	
+	suppressChangeEvent = false;	
 }
 
 Number SliderProp::get() {
-	return slider->getSliderValue();
+	return currentValue;
 }
 	
 		
@@ -413,20 +566,33 @@ NumberProp::NumberProp(String caption) : PropProp(caption, "Number") {
 
 }
 
+void NumberProp::setPropData(PolycodeEditorPropActionData* data) {
+	set(data->numVal);
+	dispatchEvent(new Event(), Event::CHANGE_EVENT);	
+}
+
 void NumberProp::handleEvent(Event *event) {
 	if(event->getDispatcher() == numberEntry) {
 		if(event->getEventType() == "UIEvent" && event->getEventCode() == UIEvent::CHANGE_EVENT) {		
-			dispatchEvent(new Event(), Event::CHANGE_EVENT);
+			lastValue = currentValue;
+			currentValue = atof(numberEntry->getText().c_str());
+			if(!suppressChangeEvent) {
+				dispatchEvent(new Event(), Event::CHANGE_EVENT);
+				dispatchEvent(new PropEvent(this, NULL, PropDataNumber(lastValue), PropDataNumber(currentValue)), PropEvent::EVENT_PROP_CHANGE);
+				
+			}
 		}
 	}
 }
 
 void NumberProp::set(Number number) {
-	numberEntry->setText(String::NumberToString(number));
+	suppressChangeEvent = true;
+	numberEntry->setText(String::NumberToString(number), false);
+	suppressChangeEvent = false;	
 }
 
 Number NumberProp::get() {
-	return atof(numberEntry->getText().c_str());
+	return currentValue;
 }
 	
 		
@@ -446,18 +612,34 @@ ColorProp::ColorProp(String caption) : PropProp(caption, "Color") {
 
 void ColorProp::handleEvent(Event *event) {
 	if(event->getDispatcher() == colorEntry) {
-		if(event->getEventType() == "UIEvent" && event->getEventCode() == UIEvent::CHANGE_EVENT) {		
-			dispatchEvent(new Event(), Event::CHANGE_EVENT);
+		if(event->getEventType() == "UIEvent" && event->getEventCode() == UIEvent::CHANGE_EVENT) {
+			lastColor = currentColor;
+			currentColor = colorEntry->getSelectedColor();
+			if(!suppressChangeEvent) {
+				dispatchEvent(new Event(), Event::CHANGE_EVENT);
+				dispatchEvent(new PropEvent(this, NULL, PropDataColor(lastColor), PropDataColor(currentColor)), PropEvent::EVENT_PROP_CHANGE);
+			}
 		}
 	}
 }
 
+
+void ColorProp::setPropData(PolycodeEditorPropActionData* data) {
+	set(data->colorVal);
+	dispatchEvent(new Event(), Event::CHANGE_EVENT);
+}
+
+
 void ColorProp::set(Color color) {
+	suppressChangeEvent = true;
 	colorEntry->setBoxColor(color);
+	lastColor = currentColor;
+	currentColor = colorEntry->getSelectedColor();	
+	suppressChangeEvent = false;	
 }
 
 Color ColorProp::get() {
-	return colorEntry->getSelectedColor();
+	return currentColor;
 }
 	
 		
@@ -466,7 +648,6 @@ ColorProp::~ColorProp() {
 }
 
 ComboProp::ComboProp(String caption) : PropProp(caption, "Combo") {
-
 	comboEntry = new UIComboBox(globalMenu, 150);
 	comboEntry->addEventListener(this, UIEvent::CHANGE_EVENT);
 	propContents->addChild(comboEntry);
@@ -475,20 +656,32 @@ ComboProp::ComboProp(String caption) : PropProp(caption, "Combo") {
 
 }
 
+void ComboProp::setPropData(PolycodeEditorPropActionData* data) {
+	set(data->intVal);
+	dispatchEvent(new Event(), Event::CHANGE_EVENT);	
+}
+
 void ComboProp::handleEvent(Event *event) {
 	if(event->getDispatcher() == comboEntry) {
 		if(event->getEventType() == "UIEvent" && event->getEventCode() == UIEvent::CHANGE_EVENT) {		
-			dispatchEvent(new Event(), Event::CHANGE_EVENT);
+			lastValue = currentValue;
+			currentValue = comboEntry->getSelectedIndex();
+			if(!suppressChangeEvent) {
+				dispatchEvent(new Event(), Event::CHANGE_EVENT);
+				dispatchEvent(new PropEvent(this, NULL, PropDataInt(lastValue), PropDataInt(currentValue)), PropEvent::EVENT_PROP_CHANGE);
+			}
 		}
 	}
 }
 
 void ComboProp::set(unsigned int index) {
+	suppressChangeEvent = true;
 	comboEntry->setSelectedIndex(index);
+	suppressChangeEvent = false;	
 }
 
 unsigned int ComboProp::get() {
-	return comboEntry->getSelectedIndex();
+	return currentValue;
 }
 	
 		
@@ -506,20 +699,30 @@ BoolProp::BoolProp(String caption) : PropProp(caption, "Bool") {
 
 }
 
+void BoolProp::setPropData(PolycodeEditorPropActionData* data) {
+	set(data->boolVal);
+	dispatchEvent(new Event(), Event::CHANGE_EVENT);	
+}
+
 void BoolProp::handleEvent(Event *event) {
 	if(event->getDispatcher() == checkEntry) {
 		if(event->getEventType() == "UIEvent" && event->getEventCode() == UIEvent::CHANGE_EVENT) {		
+			lastData = currentData;
+			currentData = checkEntry->isChecked();
 			dispatchEvent(new Event(), Event::CHANGE_EVENT);
+			dispatchEvent(new PropEvent(this, NULL, PropDataBool(lastData), PropDataBool(currentData)), PropEvent::EVENT_PROP_CHANGE);
 		}
 	}
 }
 
 void BoolProp::set(bool val) {
 	checkEntry->setChecked(val);
+	lastData = currentData;
+	currentData = checkEntry->isChecked();	
 }
 
 bool BoolProp::get() {
-	return checkEntry->isChecked();
+	return currentData;
 }
 	
 		
@@ -564,7 +767,8 @@ void SoundProp::handleEvent(Event *event) {
 		set(newSoundPath);
 		
 		globalFrame->assetBrowser->removeAllHandlersForListener(this);
-		dispatchEvent(new Event(), Event::CHANGE_EVENT);		
+		dispatchEvent(new Event(), Event::CHANGE_EVENT);
+		dispatchEvent(new PropEvent(this, NULL, PropDataString(lastData), PropDataString(currentData)), PropEvent::EVENT_PROP_CHANGE);
 		globalFrame->hideModal();
 		
 	}
@@ -586,10 +790,19 @@ void SoundProp::handleEvent(Event *event) {
 
 }
 
+void SoundProp::setPropData(PolycodeEditorPropActionData* data) {
+	set(data->stringVal);
+	dispatchEvent(new Event(), Event::CHANGE_EVENT);	
+}
+
 void SoundProp::set(String soundPath) {
 	if(previewSound) {
 		delete previewSound;
 	}	
+	
+	lastData = currentData;
+	currentData = soundPath;
+	
 	previewSound = new Sound(soundPath);	
 	soundFile->setText(soundPath);
 }
@@ -685,20 +898,19 @@ TextureProp::~TextureProp() {
 
 }
 
+void TextureProp::setPropData(PolycodeEditorPropActionData* data) {
+	set(CoreServices::getInstance()->getMaterialManager()->createTextureFromFile(data->stringVal));
+	dispatchEvent(new Event(), Event::CHANGE_EVENT);
+}
 
 void TextureProp::handleEvent(Event *event) {
 
 	if(event->getDispatcher() == globalFrame->assetBrowser && event->getEventType() == "UIEvent" && event->getEventCode() == UIEvent::OK_EVENT) {
-		String texturePath = globalFrame->assetBrowser->getSelectedAssetPath();
-				
-		previewShape->loadTexture(texturePath);
-		
-		OSFileEntry entry = OSFileEntry(texturePath, OSFileEntry::TYPE_FILE);		
-		textureLabel->setText(entry.name);		
-		
+		String texturePath = globalFrame->assetBrowser->getSelectedAssetPath();				
+		set(CoreServices::getInstance()->getMaterialManager()->createTextureFromFile(texturePath));		
 		globalFrame->assetBrowser->removeAllHandlersForListener(this);
 		dispatchEvent(new Event(), Event::CHANGE_EVENT);
-		
+		dispatchEvent(new PropEvent(this, NULL, PropDataString(lastData), PropDataString(currentData)), PropEvent::EVENT_PROP_CHANGE);
 		globalFrame->hideModal();
 		
 	}
@@ -715,6 +927,9 @@ void TextureProp::handleEvent(Event *event) {
 void TextureProp::set(Texture *texture) {
 	previewShape->setTexture(texture);
 	
+	lastData = currentData;
+	currentData = texture->getResourcePath();
+	
 	OSFileEntry entry = OSFileEntry(texture->getResourcePath(), OSFileEntry::TYPE_FILE);		
 	textureLabel->setText(entry.name);		
 	
@@ -723,6 +938,7 @@ void TextureProp::set(Texture *texture) {
 Texture* TextureProp::get() {
 	return previewShape->getTexture();
 }
+
 ScreenSpriteProp::ScreenSpriteProp(String caption) : PropProp(caption, "ScreenSprite"){
 
 		previewSprite = new ScreenSprite("default/default.sprite");
@@ -743,26 +959,16 @@ ScreenSpriteProp::~ScreenSpriteProp() {
 
 }
 
-
 void ScreenSpriteProp::handleEvent(Event *event) {
 
 	if(event->getDispatcher() == globalFrame->assetBrowser && event->getEventType() == "UIEvent" && event->getEventCode() == UIEvent::OK_EVENT) {
 		String filePath = globalFrame->assetBrowser->getSelectedAssetPath();
 		
-		if(previewSprite) {
-			propContents->removeChild(previewSprite);
-			delete previewSprite;
-		}
-		
-		previewSprite = new ScreenSprite(filePath);
-		previewSprite->setPositionMode(ScreenEntity::POSITION_TOPLEFT);
-		previewSprite->setPosition(2, 1);
-		previewSprite->setShapeSize(48,48);		
-		propContents->addChild(previewSprite);	
+		set(filePath);
 		
 		globalFrame->assetBrowser->removeAllHandlersForListener(this);
 		dispatchEvent(new Event(), Event::CHANGE_EVENT);
-		
+		dispatchEvent(new PropEvent(this, NULL, PropDataString(lastData), PropDataString(currentData)), PropEvent::EVENT_PROP_CHANGE);
 		globalFrame->hideModal();
 	}
 
@@ -775,6 +981,11 @@ void ScreenSpriteProp::handleEvent(Event *event) {
 	}
 }
 
+void ScreenSpriteProp::setPropData(PolycodeEditorPropActionData* data) {
+	set(data->stringVal);
+	dispatchEvent(new Event(), Event::CHANGE_EVENT);	
+}
+
 void ScreenSpriteProp::set(String fileName) {
 
 	if(fileName != previewSprite->getFileName()) {
@@ -783,6 +994,9 @@ void ScreenSpriteProp::set(String fileName) {
 			propContents->removeChild(previewSprite);
 			delete previewSprite;
 		}
+		lastData = currentData;
+		currentData = fileName;
+		
 		previewSprite = new ScreenSprite(fileName);
 		previewSprite->setPositionMode(ScreenEntity::POSITION_TOPLEFT);
 		previewSprite->setPosition(2, 1);
@@ -818,21 +1032,11 @@ void ScreenEntityInstanceProp::handleEvent(Event *event) {
 	if(event->getDispatcher() == globalFrame->assetBrowser && event->getEventType() == "UIEvent" && event->getEventCode() == UIEvent::OK_EVENT) {
 		String filePath = globalFrame->assetBrowser->getSelectedAssetPath();
 		
-		propContents->removeChild(previewInstance);
-		delete previewInstance;
-		previewInstance = new ScreenEntityInstance(filePath);
-		previewInstance->getResourceEntry()->reloadOnFileModify = true;
-		CoreServices::getInstance()->getResourceManager()->addResource(previewInstance->getResourceEntry());
-		previewInstance->setPosition(24, 24);
-		
-		Number radius = previewInstance->getCompoundBBoxRadius();
-		previewInstance->setScale(48.0/(radius*2.0), 48.0/(radius*2.0));
-		
-		propContents->addChild(previewInstance);
+		set(filePath);
 		
 		globalFrame->assetBrowser->removeAllHandlersForListener(this);
 		dispatchEvent(new Event(), Event::CHANGE_EVENT);
-		
+		dispatchEvent(new PropEvent(this, NULL, PropDataString(lastData), PropDataString(currentData)), PropEvent::EVENT_PROP_CHANGE);
 		globalFrame->hideModal();
 	}
 
@@ -845,6 +1049,11 @@ void ScreenEntityInstanceProp::handleEvent(Event *event) {
 	}
 }
 
+void ScreenEntityInstanceProp::setPropData(PolycodeEditorPropActionData* data) {
+	set(data->stringVal);
+	dispatchEvent(new Event(), Event::CHANGE_EVENT);
+}
+
 void ScreenEntityInstanceProp::set(String fileName) {
 
 	if(fileName != previewInstance->getFileName()) {
@@ -854,6 +1063,9 @@ void ScreenEntityInstanceProp::set(String fileName) {
 		previewInstance->setPositionMode(ScreenEntity::POSITION_TOPLEFT);
 		previewInstance->setPosition(2, 1);
 		
+		lastData = currentData;
+		currentData = fileName;
+		
 		Number radius = previewInstance->getCompoundBBoxRadius();
 		if(radius > 48) {
 			previewInstance->setScale(48.0/(radius*2.0), 48.0/(radius*2.0));		
@@ -902,7 +1114,6 @@ void ShapeSheet::handleEvent(Event *event) {
 	if(!shape)
 		return;
 
-
 	if(event->getDispatcher() == strokeProp  && event->getEventCode() == Event::CHANGE_EVENT) {
 		lastStrokeVal = strokeProp->get();
 		shape->strokeEnabled = lastStrokeVal;
@@ -912,7 +1123,7 @@ void ShapeSheet::handleEvent(Event *event) {
 	if(event->getDispatcher() == shapeSize  && event->getEventCode() == Event::CHANGE_EVENT) {
 		lastShapeSize = shapeSize->get();
 		shape->setShapeSize(lastShapeSize.x, lastShapeSize.y);
-		dispatchEvent(new Event(), Event::CHANGE_EVENT);
+		dispatchEvent(new Event(), Event::CHANGE_EVENT);	
 	}
 
 	if(event->getDispatcher() == typeProp  && event->getEventCode() == Event::CHANGE_EVENT) {
@@ -930,7 +1141,7 @@ void ShapeSheet::handleEvent(Event *event) {
 	if(event->getDispatcher() == strokeSize  && event->getEventCode() == Event::CHANGE_EVENT) {
 		lastStrokeSize = strokeSize->get();
 		shape->strokeWidth = lastStrokeSize;
-		dispatchEvent(new Event(), Event::CHANGE_EVENT);
+		dispatchEvent(new Event(), Event::CHANGE_EVENT);	
 	}
 	
 	PropSheet::handleEvent(event);
@@ -948,10 +1159,12 @@ void ShapeSheet::Update() {
 		
 		if(lastShapeType != shape->getShapeType()-1) {
 			typeProp->set(shape->getShapeType()-1);			
+			lastShapeType = shape->getShapeType()-1;			
 		}
 		
 		if(lastStrokeVal != shape->strokeEnabled) {
 			strokeProp->set(shape->strokeEnabled);
+			lastStrokeVal = shape->strokeEnabled;
 		}
 		
 		if(lastStrokeColor != shape->strokeColor) {
@@ -983,13 +1196,31 @@ EntityPropSheet::EntityPropSheet() : PropSheet("CUSTOM PROPERTIES", "entityProps
 	removeIndex = -1;
 }
 
+void EntityPropSheet::applyPropActionData(PolycodeEditorPropActionData *data) {
+	if(!entity)
+		return;
+		
+	entity->entityProps.clear();
+	for(int i=0; i < data->entity.entityProps.size(); i++) {
+			entity->entityProps.push_back(data->entity.entityProps[i]);
+	}
+	
+	refreshProps();
+}
+
+
 void EntityPropSheet::handleEvent(Event *event) {
 	if(!entity)
 		return;
 		
 	if(event->getDispatcher() == addButton && event->getEventType() == "UIEvent") {
+		PolycodeEditorPropActionData *beforeData = PropDataEntity(entity);	
 		entity->entityProps.push_back(EntityProp());
 		refreshProps();
+		PolycodeEditorPropActionData *afterData = PropDataEntity(entity);			
+		PropEvent *propEvent = new PropEvent(NULL, this, beforeData, afterData);
+		dispatchEvent(propEvent, PropEvent::EVENT_PROP_CHANGE);					
+		
 	}
 	
 	for(int i=0; i < props.size(); i++) {
@@ -999,15 +1230,19 @@ void EntityPropSheet::handleEvent(Event *event) {
 					removeIndex = i;
 				break;
 				case Event::CHANGE_EVENT:
+					PolycodeEditorPropActionData *beforeData = PropDataEntity(entity);
 					if(i < entity->entityProps.size()) {
 						entity->entityProps[i].propName = ((CustomProp*)props[i])->getKey();
 						entity->entityProps[i].propValue = ((CustomProp*)props[i])->getValue();			
 					}
+					PolycodeEditorPropActionData *afterData = PropDataEntity(entity);			
+					PropEvent *propEvent = new PropEvent(NULL, this, beforeData, afterData);
+					dispatchEvent(propEvent, PropEvent::EVENT_PROP_CHANGE);					
 				break;				
 			}
 		}
 	}
-
+	PropSheet::handleEvent(event);
 }
 
 void EntityPropSheet::refreshProps() {
@@ -1046,11 +1281,17 @@ void EntityPropSheet::Update() {
 	if(entity) {
 	
 		if(removeIndex != -1) {
+		
+			PolycodeEditorPropActionData *beforeData = PropDataEntity(entity);
+				
 			if(removeIndex < entity->entityProps.size()) {
 				entity->entityProps.erase(entity->entityProps.begin() + removeIndex);
 			}
 			removeIndex = -1;
 			refreshProps();
+			PolycodeEditorPropActionData *afterData = PropDataEntity(entity);			
+			PropEvent *propEvent = new PropEvent(NULL, this, beforeData, afterData);
+			dispatchEvent(propEvent, PropEvent::EVENT_PROP_CHANGE);
 		}
 	
 		enabled = true;		
@@ -1308,7 +1549,7 @@ EntitySheet::EntitySheet() : PropSheet("ENTITY", "entity"){
 EntitySheet::~EntitySheet() {
 
 }
-		
+
 void EntitySheet::handleEvent(Event *event) {
 
 	if(!entity)
@@ -1316,31 +1557,26 @@ void EntitySheet::handleEvent(Event *event) {
 
 	if(event->getDispatcher() == blendingProp  && event->getEventCode() == Event::CHANGE_EVENT) {
 		entity->blendingMode = blendingProp->get();
-		dispatchEvent(new Event(), Event::CHANGE_EVENT);
-	}
-
-
-	if(event->getDispatcher() == colorProp  && event->getEventCode() == Event::CHANGE_EVENT) {
+	} else if(event->getDispatcher() == colorProp  && event->getEventCode() == Event::CHANGE_EVENT) {
 		entity->color = colorProp->get();
-		dispatchEvent(new Event(), Event::CHANGE_EVENT);
-	}
-
-		
-	if(event->getDispatcher() == idProp  && event->getEventCode() == Event::CHANGE_EVENT) {
+	}else if(event->getDispatcher() == idProp  && event->getEventCode() == Event::CHANGE_EVENT) {
 		entity->id = idProp->get();
-		dispatchEvent(new Event(), Event::CHANGE_EVENT);
-	}
-
-	if(event->getDispatcher() == tagProp  && event->getEventCode() == Event::CHANGE_EVENT) {
+	} else if(event->getDispatcher() == tagProp  && event->getEventCode() == Event::CHANGE_EVENT) {
+		
+		String tagString = "";
+		for(int i=0; i < entity->getNumTags(); i++) {
+			if(i != 0) {
+				tagString += ",";
+			}
+			tagString += entity->getTagAtIndex(i);
+		}
 		
 		entity->clearTags();
 		String cleaned =  tagProp->get().replace(" ", "");
 		std::vector<String> tags = cleaned.split(",");
 		for(int i=0; i < tags.size(); i++) {
 			entity->addTag(tags[i]);
-		}
-		
-		dispatchEvent(new Event(), Event::CHANGE_EVENT);
+		}		
 	}
 	
 	PropSheet::handleEvent(event);	
@@ -1972,7 +2208,7 @@ void ScreenLabelSheet::refreshFonts() {
 ScreenLabelSheet::~ScreenLabelSheet() {
 
 }
-		
+
 void ScreenLabelSheet::handleEvent(Event *event) {
 	if(!label)
 		return;
@@ -1988,7 +2224,7 @@ void ScreenLabelSheet::handleEvent(Event *event) {
 		label->getLabel()->setFont(font);
 		label->setText(caption->get());		
 		lastFont = fontName;
-		dispatchEvent(new Event(), Event::CHANGE_EVENT);		
+		dispatchEvent(new Event(), Event::CHANGE_EVENT);
 	}
 
 
@@ -2001,7 +2237,7 @@ void ScreenLabelSheet::handleEvent(Event *event) {
 					
 		label->getLabel()->setSize(newSize);
 		label->setText(caption->get());		
-		dispatchEvent(new Event(), Event::CHANGE_EVENT);		
+		dispatchEvent(new Event(), Event::CHANGE_EVENT);
 	}
 
 
@@ -2012,33 +2248,34 @@ void ScreenLabelSheet::handleEvent(Event *event) {
 			label->getLabel()->setAntialiasMode(Label::ANTIALIAS_NONE);		
 		}		
 		label->setText(caption->get());
-		dispatchEvent(new Event(), Event::CHANGE_EVENT);		
+		dispatchEvent(new Event(), Event::CHANGE_EVENT);
 	}
-
 	
 	PropSheet::handleEvent(event);
 }
 
 void ScreenLabelSheet::Update() {
 	if(label) {
-		enabled = true;	
+		enabled = true;		
+		if(label != lastLabel) {
+			lastLabel = label;
+	
 		caption->set(label->getText());		
 		enableAA->set(label->getLabel()->getAntialiasMode() == Label::ANTIALIAS_FULL);
-		if(label->getLabel()->getSize() != lastSize) {
-			size->set(label->getLabel()->getSize());
-			lastSize = label->getLabel()->getSize();
-		}
+		size->set(label->getLabel()->getSize());
 		
 		for(int i=0; i < font->comboEntry->getNumItems(); i++) {
 			String comboFont = font->comboEntry->getItemAtIndex(i)->label;
 			
 			if(comboFont == label->getLabel()->getFont()->getFontName()) {
 				if(comboFont != lastFont) {
-					font->comboEntry->setSelectedIndex(i);
+					font->set(i);
 					lastFont = comboFont;
 				}
 			}
 		}
+
+		}
 	} else {
 		enabled = false;
 	}

+ 116 - 17
IDE/Contents/Source/PolycodeScreenEditor.cpp

@@ -738,45 +738,56 @@ PolycodeScreenEditorMain::PolycodeScreenEditorMain(PolycodeEditor *editor) {
 	
 	particleSheet = new ScreenParticleSheet();
 	particleSheet->addEventListener(this, Event::CHANGE_EVENT);	
+	particleSheet->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);		
 	entityProps->addPropSheet(particleSheet);
 
 	spriteSheet = new ScreenSpriteSheet();
-	spriteSheet->addEventListener(this, Event::CHANGE_EVENT);	
+	spriteSheet->addEventListener(this, Event::CHANGE_EVENT);
+	spriteSheet->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);	
 	entityProps->addPropSheet(spriteSheet);
 	
 	instanceSheet = new ScreenEntityInstanceSheet();
 	instanceSheet->addEventListener(this, Event::CHANGE_EVENT);	
+	instanceSheet->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);
 	entityProps->addPropSheet(instanceSheet);
 
 	labelSheet = new ScreenLabelSheet();
 	labelSheet->addEventListener(this, Event::CHANGE_EVENT);	
+	labelSheet->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);	
 	entityProps->addPropSheet(labelSheet);
 
 	soundSheet = new SoundSheet();
 	entityProps->addPropSheet(soundSheet);
 	soundSheet->addEventListener(this, Event::CHANGE_EVENT);
-
+	soundSheet->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);
+	
 	imageSheet = new ScreenImageSheet();
 	entityProps->addPropSheet(imageSheet);
 	imageSheet->addEventListener(this, Event::CHANGE_EVENT);	
-
+	imageSheet->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);
+	
 	shapeSheet = new ShapeSheet();
 	shapeSheet->addEventListener(this, Event::CHANGE_EVENT);
+	shapeSheet->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);
 	entityProps->addPropSheet(shapeSheet);
 
 	transform2dSheet = new Transform2DSheet();
 	transform2dSheet->addEventListener(this, Event::CHANGE_EVENT);
+	transform2dSheet->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);	
 	entityProps->addPropSheet(transform2dSheet);
 	
 	screenEntitySheet = new ScreenEntitySheet();
 	entityProps->addPropSheet(screenEntitySheet);
 	screenEntitySheet->addEventListener(this, Event::CHANGE_EVENT);	
-			
+	screenEntitySheet->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);
+				
 	entitySheet = new EntitySheet();
 	entityProps->addPropSheet(entitySheet);
+	entitySheet->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);
 	
 	entityPropSheet = new EntityPropSheet();
 	entityPropSheet->addEventListener(this, Event::CHANGE_EVENT);	
+	entityPropSheet->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);
 	entityProps->addPropSheet(entityPropSheet);	
 	
 	entityProps->updateProps();		
@@ -835,15 +846,18 @@ void PolycodeScreenEditorMain::doAction(String actionName, PolycodeEditorActionD
 		for(int i=0; i < selectedEntities.size(); i++) {
 			selectedEntities[i]->position = screenData->entries[i].vec3;
 		}
+		syncTransformToSelected();
 	} else if(actionName == "scale") {
 		for(int i=0; i < selectedEntities.size(); i++) {
 			selectedEntities[i]->scale = screenData->entries[i].vec3;
 		}	
+		syncTransformToSelected();		
 	} else if(actionName == "rotate") {
 		for(int i=0; i < selectedEntities.size(); i++) {
 			selectedEntities[i]->position = screenData->entries[i].vec3;		
 			selectedEntities[i]->setRotation(screenData->entries[i].number);
-		}		
+		}
+		syncTransformToSelected();			
 	} else if(actionName == "select") {
 			selectEntity(NULL, false);	
 			if(data) {
@@ -854,6 +868,7 @@ void PolycodeScreenEditorMain::doAction(String actionName, PolycodeEditorActionD
 				}					
 				multiSelect = oldMultiSelect;				
 			}
+		syncTransformToSelected();			
 	} else if(actionName == "set_current_layer") {
 		if(screenData->entry.entity) {
 			setCurrentLayer(screenData->entry.entity, false);
@@ -886,10 +901,24 @@ void PolycodeScreenEditorMain::doAction(String actionName, PolycodeEditorActionD
 				selectEntity(screenData->entries[i].entity, false);
 			}
 			multiSelect = oldMultiSelect;			
-			if(treeView) {
-				treeView->Refresh();		
-			}			
 		}
+		if(treeView) {
+			treeView->Refresh();		
+		}					
+	} else if(actionName == "create_entity") {	
+		if(screenData->reverse) {
+			deleteEntity(screenData->entry.entity);
+		} else {
+			screenData->entry.parentEntity->addChild(screenData->entry.entity);			
+		}
+		
+		if(treeView) {
+			treeView->Refresh();		
+		}			
+					
+	} else if(actionName == "prop_change") {
+		PolycodeEditorPropActionData *propData = (PolycodeEditorPropActionData*) data;
+		propData->sheet->applyPropActionData(propData);
 	}
 }
 
@@ -1388,7 +1417,14 @@ void PolycodeScreenEditorMain::handleMouseDown(Vector2 position) {
 				
 				if(treeView) {
 					treeView->Refresh();		
-				}				
+				}
+				
+				PolycodeScreenEditorActionData *beforeData = new PolycodeScreenEditorActionData();
+				PolycodeScreenEditorActionData *data = new PolycodeScreenEditorActionData();
+				data->reverse = false;
+				data->entry = PolycodeScreenEditorActionDataEntry(placingLabel);
+				beforeData->entry = PolycodeScreenEditorActionDataEntry(placingLabel);
+				editor->didAction("create_entity", beforeData, data);
 		}
 		break;		
 		case MODE_IMAGE:
@@ -1407,7 +1443,15 @@ void PolycodeScreenEditorMain::handleMouseDown(Vector2 position) {
 					
 				if(treeView) {
 					treeView->Refresh();		
-				}											
+				}	
+				
+				PolycodeScreenEditorActionData *beforeData = new PolycodeScreenEditorActionData();
+				PolycodeScreenEditorActionData *data = new PolycodeScreenEditorActionData();
+				data->reverse = false;
+				data->entry = PolycodeScreenEditorActionDataEntry(placingImage);
+				beforeData->entry = PolycodeScreenEditorActionDataEntry(placingImage);
+				editor->didAction("create_entity", beforeData, data);
+											
 		}
 		break;		
 		case MODE_SHAPE:
@@ -1426,7 +1470,15 @@ void PolycodeScreenEditorMain::handleMouseDown(Vector2 position) {
 
 				if(treeView) {
 					treeView->Refresh();		
-				}											
+				}
+				
+				PolycodeScreenEditorActionData *beforeData = new PolycodeScreenEditorActionData();
+				PolycodeScreenEditorActionData *data = new PolycodeScreenEditorActionData();
+				data->reverse = false;
+				data->entry = PolycodeScreenEditorActionDataEntry(placingShape);
+				beforeData->entry = PolycodeScreenEditorActionDataEntry(placingShape);				
+				editor->didAction("create_entity", beforeData, data);
+															
 		}
 		break;
 		case MODE_PARTICLES:
@@ -1481,7 +1533,15 @@ void PolycodeScreenEditorMain::handleMouseDown(Vector2 position) {
 				
 				if(treeView) {
 					treeView->Refresh();		
-				}											
+				}
+				
+				PolycodeScreenEditorActionData *beforeData = new PolycodeScreenEditorActionData();
+				PolycodeScreenEditorActionData *data = new PolycodeScreenEditorActionData();
+				data->reverse = false;
+				data->entry = PolycodeScreenEditorActionDataEntry(placingEmitter);
+				beforeData->entry = PolycodeScreenEditorActionDataEntry(placingEmitter);				
+				editor->didAction("create_entity", beforeData, data);
+																										
 		}
 		break;			
 		case MODE_SPRITE:
@@ -1505,7 +1565,15 @@ void PolycodeScreenEditorMain::handleMouseDown(Vector2 position) {
 
 				if(treeView) {
 					treeView->Refresh();		
-				}											
+				}
+				
+				PolycodeScreenEditorActionData *beforeData = new PolycodeScreenEditorActionData();
+				PolycodeScreenEditorActionData *data = new PolycodeScreenEditorActionData();
+				data->reverse = false;
+				data->entry = PolycodeScreenEditorActionDataEntry(placingSprite);
+				beforeData->entry = PolycodeScreenEditorActionDataEntry(placingSprite);				
+				editor->didAction("create_entity", beforeData, data);
+																										
 		}
 		break;		
 		case MODE_LINK:
@@ -1524,7 +1592,15 @@ void PolycodeScreenEditorMain::handleMouseDown(Vector2 position) {
 
 				if(treeView) {
 					treeView->Refresh();		
-				}											
+				}
+
+				PolycodeScreenEditorActionData *beforeData = new PolycodeScreenEditorActionData();
+				PolycodeScreenEditorActionData *data = new PolycodeScreenEditorActionData();
+				data->reverse = false;
+				data->entry = PolycodeScreenEditorActionDataEntry(placingInstance);
+				beforeData->entry = PolycodeScreenEditorActionDataEntry(placingInstance);				
+				editor->didAction("create_entity", beforeData, data);
+															
 		}
 		break;		
 		case MODE_ENTITY:
@@ -1546,7 +1622,16 @@ void PolycodeScreenEditorMain::handleMouseDown(Vector2 position) {
 
 				if(treeView) {
 					treeView->Refresh();		
-				}								
+				}
+
+				PolycodeScreenEditorActionData *beforeData = new PolycodeScreenEditorActionData();
+				PolycodeScreenEditorActionData *data = new PolycodeScreenEditorActionData();
+				data->reverse = false;
+				data->entry = PolycodeScreenEditorActionDataEntry(placingEntity);
+				beforeData->entry = PolycodeScreenEditorActionDataEntry(placingEntity);				
+				editor->didAction("create_entity", beforeData, data);
+				
+								
 		}
 		break;
 		case MODE_SOUND:
@@ -1571,7 +1656,16 @@ void PolycodeScreenEditorMain::handleMouseDown(Vector2 position) {
 			
 				if(treeView) {
 					treeView->Refresh();		
-				}								
+				}
+
+				PolycodeScreenEditorActionData *beforeData = new PolycodeScreenEditorActionData();
+				PolycodeScreenEditorActionData *data = new PolycodeScreenEditorActionData();
+				data->reverse = false;
+				data->entry = PolycodeScreenEditorActionDataEntry(placingSound);
+				beforeData->entry = PolycodeScreenEditorActionDataEntry(placingSound);				
+				editor->didAction("create_entity", beforeData, data);
+				
+																				
 		}
 		break;		
 	}
@@ -1938,6 +2032,11 @@ void PolycodeScreenEditorMain::handleEvent(Event *event) {
 			entityProps->scrollContainer->setScrollValue(0.0, 1.0);
 	}
 	
+	if(event->getEventCode() == PropEvent::EVENT_PROP_CHANGE) {
+		PropEvent *propEvent  = (PropEvent*) event;
+		editor->didAction("prop_change", propEvent->beforeData, propEvent->afterData);
+	}
+	
 	if((event->getDispatcher() == transform2dSheet || event->getDispatcher() == labelSheet || event->getDispatcher() == imageSheet || event->getDispatcher() == shapeSheet || event->getDispatcher() == screenEntitySheet) && event->getEventType() == "") {
 		syncTransformToSelected();
 		treeView->Refresh();		
@@ -2314,7 +2413,7 @@ void PolycodeScreenEditorMain::setMode(int newMode) {
 	parentingLine->visible = false;
 	parenting = false;
 	
-	selectEntity(NULL);
+	selectEntity(NULL, false);
 	
 	switch(mode) {
 		case MODE_SHAPE:

+ 2 - 0
Modules/Contents/UI/Include/PolyUIColorBox.h

@@ -47,6 +47,8 @@ namespace Polycode {
 			void handleEvent(Event *event);
 			void setSaturationAndValue(Number S, Number V);
 			
+			void updateColorFromMainSelector();
+			void updateColorFromHueSelector();
 			void rebuildFromTextInputs();
 			
 			void cancelColorListeners();

+ 2 - 0
Modules/Contents/UI/Include/PolyUIHSlider.h

@@ -47,6 +47,8 @@ namespace Polycode {
 		
 			Number gripPos;
 			
+			bool dragging;
+			
 			Number labelXPos;
 			Number labelYPos;
 			UIBox *bgRect;

+ 4 - 3
Modules/Contents/UI/Include/PolyUITextInput.h

@@ -1,4 +1,4 @@
-/*
+ /*
  Copyright (C) 2012 by Ivan Safrin
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -117,8 +117,9 @@ namespace Polycode {
 			 * into the text field
 			 *
 			 * @param text The new text contents.
+			 * @param sendChangeEvent If true (default), will send out an Event::CHANGE_EVENT 
 			 */
-			void setText(String text);
+			void setText(String text, bool sendChangeEvent = true);
 
 			/**
 			 * Returns the text contents of this element.
@@ -138,7 +139,7 @@ namespace Polycode {
 			 */
 			int insertLine(bool after = true);
 
-			void changedText();
+			void changedText(bool sendChangeEvent = true);
 			void applySyntaxFormatting();
 			
 			void onKeyDown(PolyKEY key, wchar_t charCode);

+ 9 - 12
Modules/Contents/UI/Source/PolyUIColorBox.cpp

@@ -301,15 +301,13 @@ void UIColorPicker::handleEvent(Event *event) {
 				InputEvent *inputEvent = (InputEvent*) event;
 				hueSelector->setPositionY(inputEvent->getMousePosition().y+hueFrame->position.y);
 				hueSelector->startDrag(inputEvent->mousePosition.x-hueSelector->getPosition().x,inputEvent->mousePosition.y-hueSelector->getPosition().y+hueFrame->position.y);		
-				Number newHue = 360.0 - (((inputEvent->getMousePosition().y-hueFrame->getPosition().y)/((hueFrame->getPosition().y+hueFrame->getHeight())-hueFrame->getPosition().y)) * 360.0f);
-				setHue(newHue);
-						
 			}
 			break;
 			case InputEvent::EVENT_MOUSEUP:
 			case InputEvent::EVENT_MOUSEUP_OUTSIDE:			
 			{
 				hueSelector->stopDrag();
+				updateColorFromHueSelector();	
 			}
 			break;	
 		}
@@ -324,17 +322,13 @@ void UIColorPicker::handleEvent(Event *event) {
 				InputEvent *inputEvent = (InputEvent*) event;
 				mainSelector->setPosition(inputEvent->getMousePosition().x+mainColorRect->position.x, inputEvent->getMousePosition().y+mainColorRect->position.y);
 				mainSelector->startDrag(inputEvent->mousePosition.x-mainSelector->getPosition().x+mainColorRect->position.x,inputEvent->mousePosition.y-mainSelector->getPosition().y+mainColorRect->position.y);
-				
-				Number newV = 1.0 - inputEvent->getMousePosition().y / mainColorRect->getHeight();
-				Number newS = inputEvent->getMousePosition().x / mainColorRect->getWidth();
-
-				setSaturationAndValue(newS, newV);
 			}
 			break;
 			case InputEvent::EVENT_MOUSEUP:
 			case InputEvent::EVENT_MOUSEUP_OUTSIDE:			
 			{
 				mainSelector->stopDrag();			
+				updateColorFromMainSelector();
 			}
 			break;	
 		}
@@ -370,8 +364,7 @@ UIColorPicker::~UIColorPicker() {
 		delete junkLabels[c];
 }
 
-void UIColorPicker::Update() {
-
+void UIColorPicker::updateColorFromMainSelector() {
 	if(mainSelector->getPosition2D() != lastMainSelectorPosition) {
 		lastMainSelectorPosition = mainSelector->getPosition2D();
 		
@@ -384,7 +377,9 @@ void UIColorPicker::Update() {
 					
 		setSaturationAndValue(newS, newV);	
 	}
-	
+}
+
+void UIColorPicker::updateColorFromHueSelector() {
 	if(hueSelector->getPosition().y != lastHueSelectorPosition) {
 		lastHueSelectorPosition = hueSelector->getPosition().y;
 		
@@ -399,8 +394,10 @@ void UIColorPicker::Update() {
 					
 		Number newHue = 360.0 - (((newPosY-hueFrame->getPosition().y)/((hueFrame->getPosition().y+hueFrame->getHeight())-hueFrame->getPosition().y)) * 360.0f);
 		setHue(newHue);
-	}	
+	}
+}
 
+void UIColorPicker::Update() {	
 	UIWindow::Update();
 }
 

+ 11 - 1
Modules/Contents/UI/Source/PolyUIHSlider.cpp

@@ -75,6 +75,7 @@ UIHSlider::UIHSlider(Number start, Number end, Number width) : UIElement() {
 	gripRect->setDragLimits(Rectangle(0,floor(bgHeight/2.0),width,0));
 	
 	gripPos = 0;
+	dragging = false;
 }
 
 UIHSlider::~UIHSlider() {
@@ -107,10 +108,15 @@ void UIHSlider::handleEvent(Event *event) {
 				gripPos = gripRect->getPosition().x;				
 				sliderValue = startValue+((endValue - startValue) * (gripPos/sliderWidth));				
 				gripRect->startDrag(inputEvent->mousePosition.x-gripRect->getPosition().x,inputEvent->mousePosition.y-gripRect->getPosition().y);
+				dragging = true;
 			break;
 			case InputEvent::EVENT_MOUSEUP:
 			case InputEvent::EVENT_MOUSEUP_OUTSIDE:
 				gripRect->stopDrag();
+				if(dragging) {
+					dispatchEvent(new UIEvent(), UIEvent::CHANGE_EVENT);
+				}
+				dragging = false;				
 			break;
 		}	
 	}
@@ -120,10 +126,15 @@ void UIHSlider::handleEvent(Event *event) {
 		switch(event->getEventCode()) {
 			case InputEvent::EVENT_MOUSEDOWN:
 				gripRect->startDrag(inputEvent->mousePosition.x-gripRect->getPosition().x,inputEvent->mousePosition.y-gripRect->getPosition().y);
+				dragging = true;				
 			break;
 			case InputEvent::EVENT_MOUSEUP:
 			case InputEvent::EVENT_MOUSEUP_OUTSIDE:		
 				gripRect->stopDrag();
+				if(dragging) {
+					dispatchEvent(new UIEvent(), UIEvent::CHANGE_EVENT);
+				}
+				dragging = false;				
 			break;
 		}	
 	}
@@ -134,6 +145,5 @@ void UIHSlider::Update() {
 	if(gripRect->getPosition().x != gripPos) {
 		gripPos = gripRect->getPosition().x;
 		sliderValue = startValue+((endValue - startValue) * (gripPos/sliderWidth));
-		dispatchEvent(new UIEvent(), UIEvent::CHANGE_EVENT);
 	}
 }

+ 6 - 4
Modules/Contents/UI/Source/PolyUITextInput.cpp

@@ -467,11 +467,13 @@ void UITextInput::applySyntaxFormatting() {
 	readjustBuffer();	
 }
 
-void UITextInput::changedText() {
+void UITextInput::changedText(bool sendChangeEvent) {
 	if(settingText)
 		return;
 	applySyntaxFormatting();
-	dispatchEvent(new UIEvent(), UIEvent::CHANGE_EVENT);	
+	if(sendChangeEvent) {
+		dispatchEvent(new UIEvent(), UIEvent::CHANGE_EVENT);	
+	}
 }
 
 void UITextInput::setSyntaxHighlighter(UITextInputSyntaxHighlighter *syntaxHighliter) {
@@ -601,7 +603,7 @@ void UITextInput::restructLines() {
 	
 }
 
-void UITextInput::setText(String text) {
+void UITextInput::setText(String text, bool sendChangeEvent) {
 	if(!multiLine) {
 		lines[lineOffset] = text;
 		caretPosition = text.length();
@@ -613,7 +615,7 @@ void UITextInput::setText(String text) {
 		clearSelection();
 	}
 //	needFullRedraw = true;		
-	changedText();
+	changedText(sendChangeEvent);
 }
 
 void UITextInput::onLoseFocus() {