示例#1
0
    public void Init(DialogueFile file, string entry)
    {
        this.file = file;
        //this.currentEntryId = entry;

        // get all the speakers in the file
        speakers.Clear();
        entrySpeakers.Clear();
        foreach (DialogueFile.DialogueEntry e in file.entries)
        {
            if (e.id == entry)
                currentEntry = e;
            foreach (string s in e.speakers)
            {
                speakers.Add(s);
                if (e.id == entry)
                {
                    entrySpeakers.Add(s);
                }
            }
        }

        speakers.ExceptWith(entrySpeakers);
        if (currentEntry.speakers == null)
            currentEntry.speakers = new List<string>();
    }
示例#2
0
    public void Init(DialogueFile file, string entry)
    {
        this.file = file;
        //this.currentEntryId = entry;

        // get all the speakers in the file
        speakers.Clear();
        entrySpeakers.Clear();
        foreach (DialogueFile.DialogueEntry e in file.entries)
        {
            if (e.id == entry)
            {
                currentEntry = e;
            }
            foreach (string s in e.speakers)
            {
                speakers.Add(s);
                if (e.id == entry)
                {
                    entrySpeakers.Add(s);
                }
            }
        }

        speakers.ExceptWith(entrySpeakers);
        if (currentEntry.speakers == null)
        {
            currentEntry.speakers = new List <string>();
        }
    }
示例#3
0
    void OnGUI()
    {
        GUILayout.BeginHorizontal();

        GUILayout.Label("New name");
        newName = GUILayout.TextField(newName);

        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();

        if (GUILayout.Button("Rename"))
        {
            // TODO rename it
            if (newName == oldName)
            {
                Close();
                return;
            }

            DialogueFile.DialogueEntry currentEntry = null;
            // check if new name already exists
            foreach (DialogueFile.DialogueEntry entry in file.entries)
            {
                if (entry.id == newName)
                {
                    EditorUtility.DisplayDialog("Error", "Dialogue with same name exists", "Ok");
                    return;
                }
                else if (entry.id == oldName)
                {
                    currentEntry = entry;
                }
            }

            currentEntry.id = newName;

            foreach (DialogueFile.DialogueLine line in file.lines)
            {
                if (line.dialogueEntry == oldName)
                {
                    line.dialogueEntry = newName;
                }
            }

            Close();
        }

        if (GUILayout.Button("Cancel"))
        {
            Close();
        }

        GUILayout.EndHorizontal();
    }
示例#4
0
	void OnGUI()
	{
		TextAnchor oldAlignment = GUI.skin.window.alignment;
		GUI.skin.window.alignment = TextAnchor.UpperLeft;

		// check if windows need to be recreated
		if (Event.current.type == EventType.Repaint && filePopupSelectedIndex >= 0 && selectedEntry != null)
			createWindows();

		GUILayout.BeginHorizontal();

		GUILayout.BeginVertical(GUILayout.Width(200));
		GUILayout.Space(5);

		GUILayout.BeginHorizontal();
		int t = filePopupSelectedIndex;
		filePopupSelectedIndex = EditorGUILayout.Popup(filePopupSelectedIndex, filePopupList);
		if (t != filePopupSelectedIndex) { } // the selected index has changed, load the correct dialogue file

		// create new dialogue file
		if (GUILayout.Button("+"))
		{
			saveUndo("creating dialogue file");
			// create new dialogueFile
			DialogueFile file = ScriptableObject.CreateInstance<DialogueFile>();
			AssetDatabase.CreateAsset(file, AssetDatabase.GenerateUniqueAssetPath("Assets/Script.asset"));
			AssetDatabase.SaveAssets();
			files.Add(file);
			buildFilePopupArray();
		}
		GUILayout.EndHorizontal();

		// import export buttons
		GUILayout.BeginHorizontal();
		if (filePopupSelectedIndex < 0)
			GUI.enabled = false;
		if (GUILayout.Button("Import"))
		{
			string filename = EditorUtility.OpenFilePanel("Import dialogue", ".", "xml");
			DialogueFile importedFile = deserializeFromXML(filename);
			// import the various entries and lines
			// check if the existing file already has the same entries
			bool foundSameEntryName = false;
			string sameEntryName = "";
			foreach (DialogueFile.DialogueEntry entry in importedFile.entries)
			{
				foreach (DialogueFile.DialogueEntry oldEntry in files[filePopupSelectedIndex].entries)
				{
					if (entry.id == oldEntry.id)
					{
						// found same entry
						foundSameEntryName = true;
						sameEntryName = entry.id;
						break;
					}
				}
			}
			bool continueImport = true;
			if (foundSameEntryName)
			{
				continueImport = EditorUtility.DisplayDialog("Same dialogue entry found", "The existing dialogue already has an entry named " + sameEntryName + ". If you continue, existing dialogues will be overwritten. Do you want to continue?", "Continue", "Cancel");
			}

			if (continueImport)
			{
				saveUndo("Importing dialogue");
				// add the entries and lines
				foreach (DialogueFile.DialogueEntry entry in importedFile.entries)
				{
					// check if it already exists
					bool dialogueExists = false;
					foreach (DialogueFile.DialogueEntry oldEntry in files[filePopupSelectedIndex].entries)
					{
						if (entry.id == oldEntry.id)
						{
							dialogueExists = true;
							// clear out existing lines
							files[filePopupSelectedIndex].lines.RemoveAll((item) => item.dialogueEntry == entry.id);
						}
					}
					if (!dialogueExists)
						files[filePopupSelectedIndex].entries.Add(entry); // add entry if it does not exists
				}

				// add the lines in one go
				files[filePopupSelectedIndex].lines.AddRange(importedFile.lines);
				EditorUtility.SetDirty(files[filePopupSelectedIndex]);
			}
		}
		if (GUILayout.Button("Export"))
		{
			// test serialization
			string filename = EditorUtility.SaveFilePanelInProject("Export dialogue", "dialogue", "xml", "");
			serializeToXML(filename, files[filePopupSelectedIndex]);
			AssetDatabase.Refresh();
		}
		if (filePopupSelectedIndex < 0)
			GUI.enabled = true;
		GUILayout.EndHorizontal();
		// draw the dialogues
		dialogueListScroll = GUILayout.BeginScrollView(dialogueListScroll, (GUIStyle)"box");

		if (filePopupSelectedIndex >= 0)
		{
			foreach (DialogueFile.DialogueEntry entry in files[filePopupSelectedIndex].entries)
			{
				if (entry == selectedEntry)
				{
					GUILayout.Label(entry.id, (GUIStyle)"boldLabel");
				}
				else
				{
					if (GUILayout.Button(entry.id, (GUIStyle)"label"))
					{
						selectedEntry = entry;
						// build windows
						createWindows();
					}
				}
			}
		}

		GUILayout.EndScrollView();

		GUILayout.BeginHorizontal();
		if (filePopupSelectedIndex < 0) GUI.enabled = false;
		if (GUILayout.Button("+"))
		{
			saveUndo("creating dialogue");
			// create new dialogue entry
			DialogueFile.DialogueEntry newEntry = new DialogueFile.DialogueEntry(createUniqueDialogueName());
			DialogueFile.DialogueLine beginLine = new DialogueFile.DialogueLine();
			beginLine.dialogueEntry = newEntry.id;
			beginLine.id = 0;
			beginLine.position = new Vector2(10, 10);
			files[filePopupSelectedIndex].entries.Add(newEntry);
			files[filePopupSelectedIndex].lines.Add(beginLine);
			EditorUtility.SetDirty(files[filePopupSelectedIndex]);
		}
		if (GUILayout.Button("-"))
		{
			saveUndo("deleting dialogue");
			// delete all the lines corresponding to this entry
			files[filePopupSelectedIndex].lines.RemoveAll((item) => item.dialogueEntry == selectedEntry.id);
			// delete the entry
			files[filePopupSelectedIndex].entries.Remove(selectedEntry);
			selectedEntry = null;
			windows.Clear();
			EditorUtility.SetDirty(files[filePopupSelectedIndex]);

		}
		if (filePopupSelectedIndex < 0) GUI.enabled = true;
		GUILayout.EndHorizontal();

		GUILayout.Space(5);
		GUILayout.EndVertical();

		GUILayout.BeginVertical();

		// show selected dialogueinfo
		GUILayout.BeginHorizontal();
		// display name
		if (selectedEntry != null) GUILayout.Label("Name: " + selectedEntry.id);
		else GUILayout.Label("Name: ");
		GUILayout.FlexibleSpace();

		if (selectedEntry == null) GUI.enabled = false;
		// rename button
		if (GUILayout.Button("Rename"))
		{
			// open rename dialog
			RenameDialogue dialog = GetWindow<RenameDialogue>(true);
			dialog.oldName = dialog.newName = selectedEntry.id;
			dialog.file = files[filePopupSelectedIndex];
		}
		if (GUILayout.Button("Edit Speakers"))
		{
			// open rename dialog
			EditSpeakers dialog = GetWindow<EditSpeakers>(true);
			dialog.Init(files[filePopupSelectedIndex], selectedEntry.id);
		}
		if (selectedEntry == null) GUI.enabled = true;
		GUILayout.EndHorizontal();

		// get rect for scrollview
		GUIStyle style = new GUIStyle();
		style.stretchHeight = true;
		style.stretchWidth = true;
		style.margin = new RectOffset(4, 4, 4, 4);
		Rect rc = GUILayoutUtility.GetRect(new GUIContent(), style);
		GUI.Box(rc, "");
		Rect bounds = getBoundingRect(new Rect(25, 25, rc.width - 50, rc.height - 50));
		bounds.x -= 25; bounds.y -= 25; bounds.width += 50; bounds.height += 50;
		dialogueTreeScroll = GUI.BeginScrollView(rc, dialogueTreeScroll, bounds);

		BeginWindows();
		int index = 0;
		bool createWindow = false;
		bool createLink = false;
		bool breakLink = false;
		bool deleteWindow = false;
		foreach (DialogueWindow window in windows)
		{
			string title = "";
			if (window.line.id == 0)
			{
				title = "BEGIN";
			}
			else
			{
				if (window.line != null) title = window.line.dialogue;
			}

			// draw output lines
			if (window.line != null)
			{
				foreach (int outputId in window.line.output)
				{
					// find connecting line
					foreach (DialogueFile.DialogueLine outputLine in files[filePopupSelectedIndex].lines)
					{
						if (outputLine.dialogueEntry == selectedEntry.id && outputLine.id == outputId)
						{
							Color color = Color.black;
							if (lastFocusWindow >= 0 && windows.Count > lastFocusWindow && windows[lastFocusWindow].line.id == outputId)
								color = Color.green;
							else if (lastFocusWindow >= 0 && windows.Count > lastFocusWindow && windows[lastFocusWindow].line == window.line)
								color = Color.red;

							Vector2 startPos = window.line.position + new Vector2(100, 25);
							Vector2 endPos = outputLine.position + new Vector2(0, 25);
							Vector2 midPos = (endPos - startPos).normalized;

							// found correct line
							float diffY = Mathf.Abs(startPos.y - endPos.y) / 4;
							float diffX = Mathf.Abs(startPos.x - endPos.x) / 4;
							Vector2 tPos = new Vector2(startPos.x + Mathf.Min(25, diffX), (startPos.y < endPos.y) ? startPos.y + Mathf.Min(25, diffY) : startPos.y - Mathf.Min(25, diffY));
							Vector2 tPos2 = new Vector2(endPos.x - Mathf.Min(25, diffX), (startPos.y < endPos.y) ? endPos.y - Mathf.Min(25, diffY) : endPos.y + Mathf.Min(25, diffY));
							Handles.DrawBezier(startPos, tPos, startPos + new Vector2(10, 0), tPos + midPos * -20, color, linetexture, 2);

							Handles.DrawBezier(tPos, tPos2, tPos + midPos * 20, tPos2 + midPos * -20, color, linetexture, 2);

							Handles.DrawBezier(tPos2, endPos, tPos2 + midPos * 20, endPos + new Vector2(-10, 0), color, linetexture, 2);
							break;
						}
					}
				}
			}

			window.rect = GUI.Window(index, window.rect, doWindow, title);

			if (window.line != null)
				window.line.position = new Vector2(window.rect.x, window.rect.y);
			//if (FocusedWindow < 0) GUI.FocusWindow(lastFocusWindow);
			GUI.FocusWindow(FocusedWindow);
			if (index == FocusedWindow)
			{
				// show extra buttons
				if (GUI.Button(new Rect(window.rect.xMax, window.rect.y + 10, 20, 20), "+", windowButtonStyle))
				{
					createWindow = true;
				}
				if (GUI.Button(new Rect(window.rect.xMax, window.rect.y + 30, 20, 20), "->", windowButtonStyle))
				{
					createLink = true;
				}
				if (GUI.Button(new Rect(window.rect.x - 20, window.rect.y + 10, 20, 20), "X", windowButtonStyle))
				{
					breakLink = true;
				}
				if (index != 0)
				{
					if (GUI.Button(new Rect(window.rect.x + 80, window.rect.y - 15, 15, 15), "x", windowButtonStyle))
					{
						deleteWindow = true;
					}
				}
			}
			lastFocusWindow = FocusedWindow;
			index++;
		}

		if (createdWindow >= 0)
		{
			GUI.BringWindowToFront(createdWindow);
			createdWindow = -1;
		}

		if (createWindow)
		{
			saveUndo("creating node");
			// create new line and window
			DialogueFile.DialogueLine line = new DialogueFile.DialogueLine();
			line.dialogue = "";
			line.dialogueEntry = selectedEntry.id;
			line.id = selectedEntry.maxLineId++;

			// set line's position
			Rect windowRc = windows[lastFocusWindow].rect;
			line.position = new Vector2(windowRc.xMax + 50, windowRc.y);

			files[filePopupSelectedIndex].lines.Add(line);

			if (windows[lastFocusWindow].line != null) windows[lastFocusWindow].line.output.Add(line.id);
			int w = addWindow(line);
			GUI.FocusWindow(w);
			createdWindow = w;

			EditorUtility.SetDirty(files[filePopupSelectedIndex]);
		}

		if (createLink)
		{
			linkDragging = true;
			linkDragStartWindow = windows[lastFocusWindow];
			wantsMouseMove = true;
		}
		if (breakLink)
		{
			linkDragging = true;
			this.breakLink = true;
			linkDragStartWindow = windows[lastFocusWindow];
			wantsMouseMove = true;
		}

		if (linkDragging)
		{
			if (Event.current.type == EventType.MouseMove)
			{
				mousePos = Event.current.mousePosition;
				Repaint();
			}

			if (this.breakLink)
			{
				// draw bezier curve from start window to cursor
				Vector2 pos1 = linkDragStartWindow.line.position + new Vector2(0, 25);
				Vector2 pos2 = mousePos;
				Handles.DrawBezier(pos1, pos2, pos1, pos2, Color.red, linetexture, 2);
			}
			else
			{
				// draw bezier curve from start window to cursor
				Vector2 pos1 = linkDragStartWindow.line.position + new Vector2(100, 25);
				Vector2 pos2 = mousePos;
				Handles.DrawBezier(pos1, pos2, pos1, pos2, Color.green, linetexture, 2);
			}
		}

		if (deleteWindow)
		{
			saveUndo("deleting node");
			// find lines that link to this one
			foreach (DialogueFile.DialogueLine line in files[filePopupSelectedIndex].lines)
			{
				if (line.dialogueEntry == windows[lastFocusWindow].line.dialogueEntry)
				{
					if (line.output.Contains(windows[lastFocusWindow].line.id))
						line.output.Remove(windows[lastFocusWindow].line.id);
				}
			}
			// remove currently selected window
			files[filePopupSelectedIndex].lines.Remove(windows[lastFocusWindow].line);
			windows.RemoveAt(lastFocusWindow);
			GUI.FocusWindow(0);
			lastFocusWindow = 0;
			EditorUtility.SetDirty(files[filePopupSelectedIndex]);
		}

		EndWindows();

		// dialogue line text area
		GUI.EndScrollView();
		if (lastFocusWindow > 0 && windows.Count > lastFocusWindow)
			windows[lastFocusWindow].line.dialogue = GUILayout.TextArea(windows[lastFocusWindow].line.dialogue, GUILayout.Height(GUI.skin.textArea.lineHeight * 3.1f));
		else
			GUILayout.TextArea("", GUILayout.Height(GUI.skin.textArea.lineHeight * 3.1f));

		GUILayout.EndVertical();

		GUILayout.EndHorizontal();
		GUI.skin.window.alignment = oldAlignment;
	}
示例#5
0
	void OnGUI()
	{
		TextAnchor oldAlignment = GUI.skin.window.alignment;
		GUI.skin.window.alignment = TextAnchor.UpperLeft;

		// check if windows need to be recreated
		if (Event.current.type == EventType.Repaint && filePopupSelectedIndex >= 0 && selectedEntry != null)
			createWindows();

		GUILayout.BeginHorizontal();

		GUILayout.BeginVertical(GUILayout.Width(200));
		GUILayout.Space(5);

		GUILayout.BeginHorizontal();
		int t = filePopupSelectedIndex;
		filePopupSelectedIndex = EditorGUILayout.Popup(filePopupSelectedIndex, filePopupList);
		if (t != filePopupSelectedIndex) { } // the selected index has changed, load the correct dialogue file

		// create new dialogue file
		if (GUILayout.Button("+"))
		{
			saveUndo("creating dialogue file");
			// create new dialogueFile
			DialogueFile file = ScriptableObject.CreateInstance<DialogueFile>();
			AssetDatabase.CreateAsset(file, AssetDatabase.GenerateUniqueAssetPath("Assets/Script.asset"));
			AssetDatabase.SaveAssets();
			files.Add(file);
			buildFilePopupArray();
		}
		GUILayout.EndHorizontal();

		// import export buttons
		GUILayout.BeginHorizontal();
		if (filePopupSelectedIndex < 0)
			GUI.enabled = false;
		if (GUILayout.Button("Import"))
		{
			string filename = EditorUtility.OpenFilePanel("Import dialogue", ".", "xml");
			DialogueFile importedFile = deserializeFromXML(filename);
			// import the various entries and lines
			// check if the existing file already has the same entries
			bool foundSameEntryName = false;
			string sameEntryName = "";
			foreach (DialogueFile.DialogueEntry entry in importedFile.entries)
			{
				foreach (DialogueFile.DialogueEntry oldEntry in files[filePopupSelectedIndex].entries)
				{
					if (entry.id == oldEntry.id)
					{
						// found same entry
						foundSameEntryName = true;
						sameEntryName = entry.id;
						break;
					}
				}
			}
			bool continueImport = true;
			if (foundSameEntryName)
			{
				continueImport = EditorUtility.DisplayDialog("Same dialogue entry found", "The existing dialogue already has an entry named " + sameEntryName + ". If you continue, existing dialogues will be overwritten. Do you want to continue?", "Continue", "Cancel");
			}

			if (continueImport)
			{
				saveUndo("Importing dialogue");
				// add the entries and lines
				foreach (DialogueFile.DialogueEntry entry in importedFile.entries)
				{
					// check if it already exists
					bool dialogueExists = false;
					foreach (DialogueFile.DialogueEntry oldEntry in files[filePopupSelectedIndex].entries)
					{
						if (entry.id == oldEntry.id)
						{
							dialogueExists = true;
							// clear out existing lines
							files[filePopupSelectedIndex].lines.RemoveAll((item) => item.dialogueEntry == entry.id);
						}
					}
					if (!dialogueExists)
						files[filePopupSelectedIndex].entries.Add(entry); // add entry if it does not exists
				}

				// add the lines in one go
				files[filePopupSelectedIndex].lines.AddRange(importedFile.lines);
				EditorUtility.SetDirty(files[filePopupSelectedIndex]);
			}
		}
		if (GUILayout.Button("Export"))
		{
			// test serialization
			string filename = EditorUtility.SaveFilePanelInProject("Export dialogue", "dialogue", "xml", "");
			serializeToXML(filename, files[filePopupSelectedIndex]);
			AssetDatabase.Refresh();
		}
		if (filePopupSelectedIndex < 0)
			GUI.enabled = true;
		GUILayout.EndHorizontal();
		// draw the dialogues
		dialogueListScroll = GUILayout.BeginScrollView(dialogueListScroll, (GUIStyle)"box");

		if (filePopupSelectedIndex >= 0)
		{
			foreach (DialogueFile.DialogueEntry entry in files[filePopupSelectedIndex].entries)
			{
				if (entry == selectedEntry)
				{
					GUILayout.Label(entry.id, (GUIStyle)"boldLabel");
				}
				else
				{
					if (GUILayout.Button(entry.id, (GUIStyle)"label"))
					{
						selectedEntry = entry;
						// build windows
						createWindows();
					}
				}
			}
		}

		GUILayout.EndScrollView();

		GUILayout.BeginHorizontal();
		if (filePopupSelectedIndex < 0) GUI.enabled = false;
		if (GUILayout.Button("+"))
		{
			saveUndo("creating dialogue");
			// create new dialogue entry
			DialogueFile.DialogueEntry newEntry = new DialogueFile.DialogueEntry(createUniqueDialogueName());
			DialogueFile.DialogueLine beginLine = new DialogueFile.DialogueLine();
			beginLine.dialogueEntry = newEntry.id;
			beginLine.id = 0;
			beginLine.position = new Vector2(10, 10);
			files[filePopupSelectedIndex].entries.Add(newEntry);
			files[filePopupSelectedIndex].lines.Add(beginLine);
			EditorUtility.SetDirty(files[filePopupSelectedIndex]);
		}
		if (GUILayout.Button("-"))
		{
			saveUndo("deleting dialogue");
			// delete all the lines corresponding to this entry
			files[filePopupSelectedIndex].lines.RemoveAll((item) => item.dialogueEntry == selectedEntry.id);
			// delete the entry
			files[filePopupSelectedIndex].entries.Remove(selectedEntry);
			selectedEntry = null;
			windows.Clear();
			EditorUtility.SetDirty(files[filePopupSelectedIndex]);

		}
		if (filePopupSelectedIndex < 0) GUI.enabled = true;
		GUILayout.EndHorizontal();

		GUILayout.Space(5);
		GUILayout.EndVertical();

		GUILayout.BeginVertical();

		// show selected dialogueinfo
		GUILayout.BeginHorizontal();
		// display name
		if (selectedEntry != null) GUILayout.Label("Name: " + selectedEntry.id);
		else GUILayout.Label("Name: ");
		GUILayout.FlexibleSpace();

		if (selectedEntry == null) GUI.enabled = false;
		// rename button
		if (GUILayout.Button("Rename"))
		{
			// open rename dialog
			RenameDialogue dialog = GetWindow<RenameDialogue>(true);
			dialog.oldName = dialog.newName = selectedEntry.id;
			dialog.file = files[filePopupSelectedIndex];
		}
		if (GUILayout.Button("Edit Speakers"))
		{
			// open rename dialog
			EditSpeakers dialog = GetWindow<EditSpeakers>(true);
			dialog.Init(files[filePopupSelectedIndex], selectedEntry.id);
		}
		if (selectedEntry == null) GUI.enabled = true;
		GUILayout.EndHorizontal();

		// get rect for scrollview
		GUIStyle style = new GUIStyle();
		style.stretchHeight = true;
		style.stretchWidth = true;
		style.margin = new RectOffset(4, 4, 4, 4);
		Rect rc = GUILayoutUtility.GetRect(new GUIContent(), style);
		GUI.Box(rc, "");
		Rect bounds = getBoundingRect(new Rect(25, 25, rc.width - 50, rc.height - 50));
		bounds.x -= 25; bounds.y -= 25; bounds.width += 50; bounds.height += 50;
		dialogueTreeScroll = GUI.BeginScrollView(rc, dialogueTreeScroll, bounds);

		BeginWindows();
		int index = 0;
		bool createWindow = false;
		bool createLink = false;
		bool breakLink = false;
		bool deleteWindow = false;
		foreach (DialogueWindow window in windows)
		{
			string title = "";
			if (window.line.id == 0)
			{
				title = "BEGIN";
			}
			else
			{
				if (window.line != null) title = window.line.dialogue;
			}

			// draw output lines
			if (window.line != null)
			{
				foreach (int outputId in window.line.output)
				{
					// find connecting line
					foreach (DialogueFile.DialogueLine outputLine in files[filePopupSelectedIndex].lines)
					{
						if (outputLine.dialogueEntry == selectedEntry.id && outputLine.id == outputId)
						{
							Color color = Color.black;
							if (lastFocusWindow >= 0 && windows.Count > lastFocusWindow && windows[lastFocusWindow].line.id == outputId)
								color = Color.green;
							else if (lastFocusWindow >= 0 && windows.Count > lastFocusWindow && windows[lastFocusWindow].line == window.line)
								color = Color.red;

							Vector2 startPos = window.line.position + new Vector2(100, 25);
							Vector2 endPos = outputLine.position + new Vector2(0, 25);
							Vector2 midPos = (endPos - startPos).normalized;

							// found correct line
							float diffY = Mathf.Abs(startPos.y - endPos.y) / 4;
							float diffX = Mathf.Abs(startPos.x - endPos.x) / 4;
							Vector2 tPos = new Vector2(startPos.x + Mathf.Min(25, diffX), (startPos.y < endPos.y) ? startPos.y + Mathf.Min(25, diffY) : startPos.y - Mathf.Min(25, diffY));
							Vector2 tPos2 = new Vector2(endPos.x - Mathf.Min(25, diffX), (startPos.y < endPos.y) ? endPos.y - Mathf.Min(25, diffY) : endPos.y + Mathf.Min(25, diffY));
							Handles.DrawBezier(startPos, tPos, startPos + new Vector2(10, 0), tPos + midPos * -20, color, linetexture, 2);

							Handles.DrawBezier(tPos, tPos2, tPos + midPos * 20, tPos2 + midPos * -20, color, linetexture, 2);

							Handles.DrawBezier(tPos2, endPos, tPos2 + midPos * 20, endPos + new Vector2(-10, 0), color, linetexture, 2);
							break;
						}
					}
				}
			}

			window.rect = GUI.Window(index, window.rect, doWindow, title);

			if (window.line != null)
				window.line.position = new Vector2(window.rect.x, window.rect.y);
			//if (FocusedWindow < 0) GUI.FocusWindow(lastFocusWindow);
			GUI.FocusWindow(FocusedWindow);
			if (index == FocusedWindow)
			{
				// show extra buttons
				if (GUI.Button(new Rect(window.rect.xMax, window.rect.y + 10, 20, 20), "+", windowButtonStyle))
				{
					createWindow = true;
				}
				if (GUI.Button(new Rect(window.rect.xMax, window.rect.y + 30, 20, 20), "->", windowButtonStyle))
				{
					createLink = true;
				}
				if (GUI.Button(new Rect(window.rect.x - 20, window.rect.y + 10, 20, 20), "X", windowButtonStyle))
				{
					breakLink = true;
				}
				if (index != 0)
				{
					if (GUI.Button(new Rect(window.rect.x + 80, window.rect.y - 15, 15, 15), "x", windowButtonStyle))
					{
						deleteWindow = true;
					}
				}
			}
			lastFocusWindow = FocusedWindow;
			index++;
		}

		if (createdWindow >= 0)
		{
			GUI.BringWindowToFront(createdWindow);
			createdWindow = -1;
		}

		if (createWindow)
		{
			saveUndo("creating node");
			// create new line and window
			DialogueFile.DialogueLine line = new DialogueFile.DialogueLine();
			line.dialogue = "";
			line.dialogueEntry = selectedEntry.id;
			line.id = selectedEntry.maxLineId++;

			// set line's position
			Rect windowRc = windows[lastFocusWindow].rect;
			line.position = new Vector2(windowRc.xMax + 50, windowRc.y);

			files[filePopupSelectedIndex].lines.Add(line);

			if (windows[lastFocusWindow].line != null) windows[lastFocusWindow].line.output.Add(line.id);
			int w = addWindow(line);
			GUI.FocusWindow(w);
			createdWindow = w;

			EditorUtility.SetDirty(files[filePopupSelectedIndex]);
		}

		if (createLink)
		{
			linkDragging = true;
			linkDragStartWindow = windows[lastFocusWindow];
			wantsMouseMove = true;
		}
		if (breakLink)
		{
			linkDragging = true;
			this.breakLink = true;
			linkDragStartWindow = windows[lastFocusWindow];
			wantsMouseMove = true;
		}

		if (linkDragging)
		{
			if (Event.current.type == EventType.MouseMove)
			{
				mousePos = Event.current.mousePosition;
				Repaint();
			}

			if (this.breakLink)
			{
				// draw bezier curve from start window to cursor
				Vector2 pos1 = linkDragStartWindow.line.position + new Vector2(0, 25);
				Vector2 pos2 = mousePos;
				Handles.DrawBezier(pos1, pos2, pos1, pos2, Color.red, linetexture, 2);
			}
			else
			{
				// draw bezier curve from start window to cursor
				Vector2 pos1 = linkDragStartWindow.line.position + new Vector2(100, 25);
				Vector2 pos2 = mousePos;
				Handles.DrawBezier(pos1, pos2, pos1, pos2, Color.green, linetexture, 2);
			}
		}

		if (deleteWindow)
		{
			saveUndo("deleting node");
			// find lines that link to this one
			foreach (DialogueFile.DialogueLine line in files[filePopupSelectedIndex].lines)
			{
				if (line.dialogueEntry == windows[lastFocusWindow].line.dialogueEntry)
				{
					if (line.output.Contains(windows[lastFocusWindow].line.id))
						line.output.Remove(windows[lastFocusWindow].line.id);
				}
			}
			// remove currently selected window
			files[filePopupSelectedIndex].lines.Remove(windows[lastFocusWindow].line);
			windows.RemoveAt(lastFocusWindow);
			GUI.FocusWindow(0);
			lastFocusWindow = 0;
			EditorUtility.SetDirty(files[filePopupSelectedIndex]);
		}

		EndWindows();

		// dialogue line text area
		GUI.EndScrollView();
		if (lastFocusWindow > 0 && windows.Count > lastFocusWindow)
			windows[lastFocusWindow].line.dialogue = GUILayout.TextArea(windows[lastFocusWindow].line.dialogue, GUILayout.Height(GUI.skin.textArea.lineHeight * 3.1f));
		else
			GUILayout.TextArea("", GUILayout.Height(GUI.skin.textArea.lineHeight * 3.1f));

		GUILayout.EndVertical();

		GUILayout.EndHorizontal();
		GUI.skin.window.alignment = oldAlignment;
	}