To be able to save our data we'll of
course need to have our Save button. We'll start by creating a basic toolbar that
will hold both the file name and the save button, that will be disabled or enabled depending if there is a name
error or not in the graph. So to create our Toolbar let's head to our Editor Window script and under our "AddGraphView" method, we'll call a new method
we'll create named "AddToolbar". I'll add this method to our "Elements Addition"
region under our "AddGraphView" method. In here, we'll have to create a new
toolbar and add elements into it. Thankfully, Unity already provides us with a Toolbar class that we can use to create it, so type in "Toolbar" and import its namespace. Then, I'll name it "toolbar" and call its constructor. We now add this toolbar to the editor
"rootVisualElement" variable by typing in "rootVisualElement.Add(toolbar)". We will want to add two things to this toolbar for now: The TextField that will hold the graph name, which will also be the dialogues parent folder name, and the Save Button, that will call our Save method later on. So let's create a new TextField to which
I'll name "fileNameTextField" and use our "DSElementUtility" class to create the text field,
so type in "DSElementUtility.CreateTextField()" and in here we'll want the
default name for our graph. I'll create a private variable above for that of
type string and I'll name it "defaultFileName". Give it any value you'd want, I'll give
it the value of "DialoguesFileName". Because we won't be updating this value
we can make the variable be "readonly". You could make it a constant or
something else if you wanted to. I just made the one Visual Studio recommended me. We can now pass in this variable as our TextField text. We also want to pass in a label so that the user
knows this is a text field for the file name, so we'll have to go to our CreateTextField method
and add a new parameter of type string to which I'll name "label" and default it to "null". Then, pass it in in the Object Initializer. We should do the same for our Text Area
method so add the same parameter there and pass it in to the "CreateTextField" method. This will throw errors whenever we are
calling these methods with a callback so go there and make sure you pass in "null"
for the label in each of the method calls. Back to our Editor Window "AddToolbar" method,
pass in as a label the text of "File Name:". All that's left is our save button, so create
a new variable of type "Button" to which I'll name "saveButton" and create it
using our element utility by typing in "DSElementUtility.CreateButton("Save")", we won't be setting the callback for now. All that's left is to add these
elements to the toolbar so type in "toolbar.Add(fileNameTextField)"
and do the same for our "saveButton". We now have our toolbar added so
if we save and go back to Unity, we should be able to see our Toolbar at the top. We should now start by disabling our
Save button whenever we have an error in our graph and enabling it again
when there are no more errors left. We'll actually do that by using
a property of type integer, but instead of doing an automatic
property we will do our own setter. What we'll do is quite simple: Every time a repeated name error happens,
we'll increment 1 to the value of the property. Every time a repeated name is no longer a repeated name,
we'll decrement 1 to the value of the property. Whenever the current value of the property is "0",
we can Enable our Save button. Otherwise, whenever it is over "0", it means there are errors in our Graph, so we should Disable our Save button. So back to our GraphView, we'll actually
have to create two variables because our property won't be automatic anymore. So we'll have to do it the normal way, which is create a private variable and then create a public
one that gets and sets that private variable. So type in "private int" and I'll
name it "repeatedNamesAmount". Then, create a new one by typing in "public int" and I'll name it the same but with
the first letter being uppercase. Once that's done, we'll need to
set our property get and set. So type in "get and between curly brackets
type in return repeatedNamesAmount". For our "set" type in "set"
and between curly brackets we'll be setting our value and also
update the state of our Save button. Let's start by setting our value by typing in
"repeatedNamesAmount" and set it to be "value". This value is from the property and simply holds
the new value that this property will have, which will either be minus 1 or plus 1
than it's previous value in our case. Then, we'll have an if statement to
see if the value is now 0 or not, so type in "if (repeatedNamesAmount == 0)", and if that's true we will want to enable our Save Button, so I'll type in a comment for now saying "// Enable Save Button". Otherwise, we'll have to disable it. You can either do it when the value
is "1" or every time it's not "0". I don't think it will have a big
performance impact but I'll type in a new if statement instead of "else",
so "if (repeatedNamesAmount == 1)" and type in a comment saying "// Disable Save Button". Of course, feel free to do it as you desire, as unless you are creating every node right off the bat without updating their names, the
"else" statement is likely to not happen a lot. We have our property so we now need to create our methods that allow us to enable or disable the save button. We'll actually do that in our
Editor Window so let's head there, and let's start by making a global Button
variable to which I'll name "saveButton". We can then remove the "Button"
type in our "AddToolbar" method. This variable is just so we can
update the state of our save button in our yet to be created methods. So let's create the enable method by
typing in "public void EnableSaving()" and I'll place this method inside
of a region named "Utility Methods". Inside, we'll simply have to enable the button so type in "saveButton.SetEnabled(true)". For disabling, we will of course be doing the opposite, we will need to pass in "false". So copy the method above
and swap the "Enable" with "Disable" instead and then pass in "false" instead of "true". Back to our Graph View, we can now swap
the comments with the correct methods, so swap the first comment with
"editorWindow.EnableSaving()" and then swap the second comment
with "editorWindow.DisableSaving()". We now need to update the value of our property. And we'll do that in all of
our Add and Remove methods. In our Add methods, whenever the count gets to
"2", we should increment 1 to the property value, as that's when we know a new
repeated name has occurred. In our Remove methods, whenever the count gets to "1", we should decrement 1 to the property value, as that's when we know
that name is no longer a repeated name. So let's go to our "AddUngroupedNode" method
and in our last if check statement type in "++RepeatedNamesAmount". This will add 1 to the repeated file names int property whenever we add a new node
and there was already one with the same name. Because this is in the if check
statement when the count is equal to "2", it will only happen once per name. Then, in our "RemoveUngroupedNode" method
we decrement one when our count gets to "1", as it means it was previously "2" but the
second node with the same name was removed, so it should no longer throw an error. So type in "--RepeatedNamesAmount". Do the same in all our other "4" methods. Saving and going back to Unity, our Save button should now enable or disable
depending if there is an error or not in the Graph. With that done, our basic toolbar functionality is done, but of course, it's styles are not
looking like the rest of our system. We will update their styles by creating a new style sheet for our Toolbar and then updating whatever we want there. So go to our "Editor Default Resources" folder and in our "DialogueSystem" folder create a new Style Sheet by right clicking in the project window, going to
"Create", "UI Toolkit" and choose "Style Sheet". I'll name it "DSToolbarStyles". Thankfully for us, most of our styles
are equal to what we have in our node, so we'll be able to get most of it from there. We will however have some slight differences
like whenever a label is focused, as I want to show it with a golden color. This will allow us to know our file name text field is selected and will make it seem a bit more important. The best option would be to have a
style sheet that holds the styles that are equal so that we could simply
reuse them between different elements, so if you want to do that feel
free to go ahead and do it. I'll just do it this way for no particular reason besides deciding early on that I
would do one style sheet per type. We will start with our Toolbar so
type in "Toolbar" as the selector and we'll be updating its
background color and its height. So "background-color" and we already
have the color I want to give it so "var(--ds-colors-window-dark-grey-1)". For our height, we'll give it
"var(--ds-metrics-window-pixels-35)". This will make our Toolbar darker and be taller. Then, we'll update the "TextField"
and give it a padding of 4 pixels. So "padding: var(--ds-metrics-window-pixels-4)". Next are our buttons. We can actually use the same styles
as our nodes here so let's go to our node styles and copy our Buttons in all of the 3 states. We will update the selector to only be "Button". The reason why I'm not caring too
much about classes here is becaus we will be adding our style sheet to the
toolbar itself as there will only be one, which in our nodes case
we added the whole style sheet to the GraphView which takes more than nodes. Next, let's update our label to
also have a padding of 4 pixels. We'll be using an unity selector for this
so type in ".unity-text-field__label" and pass in "padding: var(--ds-metrics-window-pixels-4)". The next one will make it so that the label
gets golden when we focus on the Text Field, so I'll type in "TextField:focus >"
and then the same selector as above. Then, update the "color:" to be
"var(--ds-colors-window-yellow)". Then, we'll update the text field
input and we can use our node styles here so copy them and paste it in in our toolbar styles. Feel free to remove the initial node class selector. We will however update a few styles. Remove the "max-width" and make it a "max-height" instead passing in "25" pixels. For the "min-width" pass in "120", in which we'll need to add an extra
variable in our style variables. For our "padding", we'll make it
"padding-left" and swap the pixels to be "6". We will also need to add an extra variable for this one. Then, we'll want to update its color to yellow when it is focused so type in the same class selector
but with the ":focus" pseudo-class. And then type in "color: var(--ds-colors-window-yellow)". Feel free to remove this one if you don't want the text field input
text to be yellow when it's selected. The styles are done so all that's left
is to add the style sheet to our toolbar. Let's head back to our Editor Window Script and
in our "AddToolbar" method type in at the end just above our rootVisualElement line "toolbar.AddStyleSheets()" and pass in the path "DialogueSystem/DSToolbarStyles.uss". Saving and going back to Unity, our
toolbar should now have our styles.