From 594e4257e0b1cc29865c3b8a2bf44fd41fa29d90 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Sun, 1 Sep 2019 23:03:38 -0700 Subject: [PATCH] Implemented text input into float fields. Small fixes to the node search bar, beginning to pull it out into a standalone piece. --- foldhaus_app.cpp | 138 ++++++++++++++++++++++++--------------- foldhaus_app.h | 13 ++-- foldhaus_interface.cpp | 5 +- foldhaus_interface.h | 23 ------- foldhaus_node.cpp | 21 ++++-- foldhaus_node.h | 11 ++-- foldhaus_search_lister.h | 33 ++++++++++ foldhaus_text_entry.cpp | 75 ++++++++++++++++----- foldhaus_text_entry.h | 23 ++++++- interface.h | 15 +---- todo.txt | 3 +- 11 files changed, 232 insertions(+), 128 deletions(-) create mode 100644 foldhaus_search_lister.h diff --git a/foldhaus_app.cpp b/foldhaus_app.cpp index a5084f3..6f9d3dd 100644 --- a/foldhaus_app.cpp +++ b/foldhaus_app.cpp @@ -348,7 +348,7 @@ RELOAD_STATIC_DATA(ReloadStaticData) CameraMouseControl); RegisterKeyPressCommand(&State->InputCommandRegistry, KeyCode_U, false, KeyCode_Invalid, ToggleUniverseDebugView); RegisterMouseWheelCommand(&State->InputCommandRegistry, CameraMouseZoom); - RegisterKeyPressCommand(&State->InputCommandRegistry, KeyCode_A, false, KeyCode_Invalid, AddNode); + RegisterKeyPressCommand(&State->InputCommandRegistry, KeyCode_A, false, KeyCode_Invalid, OpenNodeLister); RegisterKeyPressCommand(&State->InputCommandRegistry, KeyCode_Tab, false, KeyCode_Invalid, ToggleNodeDisplay); InitializeTextInputCommands(&State->TextEntryCommandRegistry, State->Permanent); @@ -370,6 +370,8 @@ INITIALIZE_APPLICATION(InitializeApplication) InitializeInputCommandRegistry(&State->TextEntryCommandRegistry, 32, State->Permanent); State->ActiveCommands = &State->InputCommandRegistry; + State->ActiveTextEntry.Buffer = MakeString(PushArray(State->Permanent, char, 256), 0, 256); + // TODO(Peter): put in InitializeInterface? r32 FontSize = 14; { @@ -451,10 +453,6 @@ INITIALIZE_APPLICATION(InitializeApplication) LoadAssembly(State, Context, Path); #endif - State->InterfaceState.AddingPattern = false; - State->InterfaceState.PatternSelectorStart = 0; - State->InterfaceState.ChannelSelected = -1; - State->InterfaceYMax = 200; State->PixelsToWorldScale = .01f; State->Camera_StartDragPos = {}; @@ -466,7 +464,7 @@ INITIALIZE_APPLICATION(InitializeApplication) State->NodeList = AllocateNodeList(State->Permanent, Kilobytes(64)); - State->NodeInteraction = NewNodeInteraction(); + State->NodeInteraction = NewEmptyNodeInteraction(); State->NodeRenderSettings.PortDim = v2{20, 15}; State->NodeRenderSettings.PortStep = State->NodeRenderSettings.PortDim.y + 10; State->NodeRenderSettings.PortColors[MemberType_r32] = RedV4; @@ -476,8 +474,7 @@ INITIALIZE_APPLICATION(InitializeApplication) State->OutputNode = PushOutputNodeOnList(State->NodeList, v2{500, 250}, State->Permanent); - State->GeneralPurposeSearch.Backbuffer = PushArray(State->Permanent, char, 256); - InitializeEmptyString(&State->GeneralPurposeSearch.Buffer, State->GeneralPurposeSearch.Backbuffer, 256); + InitializeEmptyString(&State->GeneralPurposeSearchString, PushArray(State->Permanent, char, 256), 256); ReloadStaticData(Context, GlobalDebugServices); } @@ -494,7 +491,7 @@ UPDATE_AND_RENDER(UpdateAndRender) if (State->ActiveCommands == &State->TextEntryCommandRegistry) { - AppendInputToEntryString(State->ActiveTextEntry, Input.New->StringInput, Input.New->StringInputUsed); + AppendInputToEntryString(&State->ActiveTextEntry, Input.New->StringInput, Input.New->StringInputUsed); } ExecuteAllRegisteredCommands(State->ActiveCommands, Input, State); @@ -736,40 +733,78 @@ UPDATE_AND_RENDER(UpdateAndRender) /////////////////////////////////////// // Figuring Out Nodes ////////////////////////////////////// + + v2 MousePos = v2{(r32)Input.New->MouseX, (r32)Input.New->MouseY}; + v2 LastFrameMousePos = v2{(r32)Input.Old->MouseX, (r32)Input.Old->MouseY}; + + if (KeyTransitionedDown(Input, KeyCode_MouseLeftButton)) + { + node_offset Node = GetNodeUnderPoint(State->NodeList, MousePos, State->NodeRenderSettings); + if (Node.Node) + { + State->NodeInteraction = GetNodeInteractionType(Node.Node, Node.Offset, MousePos, State->NodeRenderSettings); + } + } + else if (KeyTransitionedUp(Input, KeyCode_MouseLeftButton)) + { + if (IsDraggingNodePort(State->NodeInteraction)) + { + TryConnectNodes(State->NodeInteraction, MousePos, State->NodeList, State->NodeRenderSettings); + State->NodeInteraction = NewEmptyNodeInteraction(); + } + else if(IsDraggingNodeValue(State->NodeInteraction)) + { + v2 MouseDelta = MousePos - LastFrameMousePos; + + // This is just a click + if (Mag(MouseDelta) < 10) + { + node_interaction Interaction = State->NodeInteraction; + interface_node* Node = GetNodeAtOffset(State->NodeList, Interaction.NodeOffset); + node_connection* Connection = Node->Connections + Interaction.InputValue; + struct_member_type InputType = Connection->Type; + if (InputType == MemberType_r32) + { + SetTextInputDestinationToFloat(&State->ActiveTextEntry, &Connection->R32Value); + } + State->NodeInteraction = NewEmptyNodeInteraction(); + State->ActiveCommands = &State->TextEntryCommandRegistry; + } + else // This is the case where you dragged the value + { + State->NodeInteraction = NewEmptyNodeInteraction(); + } + } + else + { + State->NodeInteraction = NewEmptyNodeInteraction(); + } + + } + + UpdateDraggingNode(MousePos, State->NodeInteraction, State->NodeList, + State->NodeRenderSettings); + UpdateDraggingNodePort(MousePos, State->NodeInteraction, State->NodeList, + State->NodeRenderSettings, RenderBuffer); + UpdateDraggingNodeValue(MousePos, LastFrameMousePos, State->NodeInteraction, State->NodeList, State->NodeRenderSettings, State); + + ResetNodesUpdateState(State->NodeList); + if (State->NodeRenderSettings.Display) { - v2 MousePos = v2{(r32)Input.New->MouseX, (r32)Input.New->MouseY}; - v2 LastFrameMousePos = v2{(r32)Input.Old->MouseX, (r32)Input.Old->MouseY}; - - if (KeyTransitionedDown(Input, KeyCode_MouseLeftButton)) - { - node_offset Node = GetNodeUnderPoint(State->NodeList, MousePos, State->NodeRenderSettings); - if (Node.Node) - { - State->NodeInteraction = GetNodeInteractionType(Node.Node, Node.Offset, MousePos, State->NodeRenderSettings); - } - } - else if (KeyTransitionedUp(Input, KeyCode_MouseLeftButton)) - { - if (IsDraggingNodePort(State->NodeInteraction)) - { - TryConnectNodes(State->NodeInteraction, MousePos, State->NodeList, State->NodeRenderSettings); - } - State->NodeInteraction = NewNodeInteraction(); - } - - UpdateDraggingNode(MousePos, State->NodeInteraction, State->NodeList, - State->NodeRenderSettings); - UpdateDraggingNodePort(MousePos, State->NodeInteraction, State->NodeList, - State->NodeRenderSettings, RenderBuffer); - UpdateDraggingNodeValue(MousePos, LastFrameMousePos, State->NodeInteraction, State->NodeList, State->NodeRenderSettings, State); - RenderNodeList(State->NodeList, State->NodeRenderSettings, RenderBuffer); - ResetNodesUpdateState(State->NodeList); - if (State->InterfaceShowNodeList) { + if (KeyTransitionedDown(Input, KeyCode_DownArrow)) + { + SearchListerNextItem(State, Input); + } + if (KeyTransitionedDown(Input, KeyCode_UpArrow)) + { + SearchListerPrevItem(State, Input); + } + v2 TopLeft = State->NodeListMenuPosition; v2 Dimension = v2{300, 30}; @@ -778,28 +813,27 @@ UPDATE_AND_RENDER(UpdateAndRender) NodeSpecificationsCount, (u8*)NodeSpecifications, State->GeneralPurposeSearchHotItem, NodeListerGetNodeName, - &State->GeneralPurposeSearch.Buffer, - State->GeneralPurposeSearch.CursorPosition, + &State->ActiveTextEntry.Buffer, + State->ActiveTextEntry.CursorPosition, State->Font, State->Interface, Input); State->GeneralPurposeSearchHotItem = NodeListResult.HotItem; - if (KeyTransitionedDown(Input, KeyCode_MouseLeftButton) || - KeyTransitionedDown(Input, KeyCode_Esc)) - { - State->InterfaceShowNodeList = false; - DeactivateTextEntry(State); - } - if (KeyTransitionedDown(Input, KeyCode_Enter)) { - State->InterfaceShowNodeList = false; - if (NodeListResult.HotItem > 0) - { - PushNodeOnListFromSpecification(State->NodeList, NodeSpecifications[NodeListResult.HotItem], - MousePos, State->NodeRenderSettings, State->Permanent); - } + NodeListResult.SelectedItem = NodeListResult.HotItem; } + if (NodeListResult.SelectedItem >= 0) + { + PushNodeOnListFromSpecification(State->NodeList, NodeSpecifications[NodeListResult.SelectedItem], + MousePos, State->NodeRenderSettings, State->Permanent); + CloseSearchLister(State, Input); + } + else if (KeyTransitionedDown(Input, KeyCode_MouseLeftButton) || + KeyTransitionedDown(Input, KeyCode_Esc)) + { + CloseSearchLister(State, Input); + } } } diff --git a/foldhaus_app.h b/foldhaus_app.h index 1c9e992..b8ff012 100644 --- a/foldhaus_app.h +++ b/foldhaus_app.h @@ -51,6 +51,7 @@ typedef struct app_state app_state; #include "foldhaus_debug_visuals.h" #include "foldhaus_command_dispatch.h" + #include "foldhaus_text_entry.h" #include "foldhaus_default_nodes.h" @@ -62,18 +63,12 @@ struct app_state memory_arena* Transient; memory_arena SACNMemory; - /* - render_texture* LoadedTextures; - s32 LoadedTexturesSize; - s32 LoadedTexturesUsed; - */ - camera Camera; input_command_registry InputCommandRegistry; input_command_registry TextEntryCommandRegistry; input_command_registry* ActiveCommands; - text_input* ActiveTextEntry; + text_input ActiveTextEntry; streaming_acn SACN; s32 TotalLEDsCount; @@ -87,7 +82,6 @@ struct app_state s32 AssembliesUsed; bitmap_font* Font; - interface_state InterfaceState; interface_config Interface; r32 InterfaceYMax; @@ -108,11 +102,12 @@ struct app_state v4* ColorPickerEditValue; - text_input GeneralPurposeSearch; + string GeneralPurposeSearchString; s32 GeneralPurposeSearchHotItem; }; +#include "foldhaus_search_lister.h" #include "foldhaus_sacn_view.cpp" #include "foldhaus_command_dispatch.cpp" #include "foldhaus_node.cpp" diff --git a/foldhaus_interface.cpp b/foldhaus_interface.cpp index 0fac442..3122d13 100644 --- a/foldhaus_interface.cpp +++ b/foldhaus_interface.cpp @@ -50,11 +50,12 @@ FOLDHAUS_INPUT_COMMAND_PROC(ToggleUniverseDebugView) } -FOLDHAUS_INPUT_COMMAND_PROC(AddNode) +FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeLister) { State->InterfaceShowNodeList = true; State->NodeListMenuPosition = v2{(r32)Input.New->MouseX, (r32)Input.New->MouseY}; - ActivateTextEntry(&State->GeneralPurposeSearch, State); + SetTextInputDestinationToString(&State->ActiveTextEntry, &State->GeneralPurposeSearchString); + State->ActiveCommands = &State->TextEntryCommandRegistry; } FOLDHAUS_INPUT_COMMAND_PROC(ToggleNodeDisplay) diff --git a/foldhaus_interface.h b/foldhaus_interface.h index 9775024..e69de29 100644 --- a/foldhaus_interface.h +++ b/foldhaus_interface.h @@ -1,23 +0,0 @@ -enum interface_selection_type -{ - InterfaceSelection_None, - InterfaceSelection_Channel, - InterfaceSelection_Pattern, -}; - -struct interface_state -{ - b32 AddingPattern; - - s32 ChannelSelectorStart; - s32 ChannelSelected; - - s32 ActiveChannelPatternSelectorStart; - s32 ActiveChannelPatternSelected; - - s32 PatternSelectorStart; - - b32 ChooseOperationPanelOpen; - - interface_selection_type SelectionType; -}; diff --git a/foldhaus_node.cpp b/foldhaus_node.cpp index ba0ffa9..b8b342d 100644 --- a/foldhaus_node.cpp +++ b/foldhaus_node.cpp @@ -271,7 +271,7 @@ CalculateNodeDragHandleBounds (rect NodeBounds, s32 Index, node_render_settings } internal node_interaction -NewNodeInteraction () +NewEmptyNodeInteraction () { node_interaction Result = {}; Result.NodeOffset = -1; @@ -282,6 +282,19 @@ NewNodeInteraction () return Result; } +internal node_interaction +NewNodeInteraction (s32 NodeOffset, v2 MouseOffset) +{ + node_interaction Result = {}; + Result.NodeOffset = NodeOffset; + Result.MouseOffset = MouseOffset; + Result.InputPort = -1; + Result.InputValue = -1; + Result.OutputPort = -1; + Result.OutputValue = -1; + return Result; +} + internal b32 IsDraggingNode (node_interaction Interaction) { @@ -431,7 +444,6 @@ ConnectionIsOutput (interface_node* Node, s32 ConnectionIdx) return ConnectionIsOutput(Node->Connections[ConnectionIdx]); } - internal b32 CheckForRecursion (node_list* NodeList, s32 LookForNode, interface_node* StartNode) { @@ -535,10 +547,7 @@ GetNodeInteractionType (interface_node* ActiveNode, s32 NodeOffset, v2 MousePos, { DEBUG_TRACK_FUNCTION; - node_interaction Interaction = NewNodeInteraction(); - - Interaction.NodeOffset = NodeOffset; - Interaction.MouseOffset = ActiveNode->Min - MousePos; + node_interaction Interaction = NewNodeInteraction(NodeOffset, ActiveNode->Min - MousePos); rect NodeBounds = CalculateNodeBounds(ActiveNode, RenderSettings); diff --git a/foldhaus_node.h b/foldhaus_node.h index 1341370..e4623a9 100644 --- a/foldhaus_node.h +++ b/foldhaus_node.h @@ -21,10 +21,10 @@ s32 name##LEDCount; enum mouse_node_interaction { - MouseNodeInteraction_None, - MouseNodeInteraction_DragNode, - MouseNodeInteraction_DragInput, - + NodeInteraction_None, + NodeInteraction_MouseDragNode, + NodeInteraction_MouseDragInput, + NodeInteraction_KeyboardEnterPortValue, MouseNodeInteraction_Count, }; @@ -37,6 +37,7 @@ enum node_port_direction // TODO(Peter): Generate this enum struct_member_type { + MemberType_Invalid, MemberType_s32, MemberType_r32, MemberType_v4, @@ -121,6 +122,8 @@ struct node_interaction v2 MouseOffset; b32 Flags; + // TODO(Peter): Inputs and outputs are all stored in the same array. Should this just be flags, + // and we store the Port and Value? s32 InputPort; s32 InputValue; s32 OutputPort; diff --git a/foldhaus_search_lister.h b/foldhaus_search_lister.h new file mode 100644 index 0000000..a81e82c --- /dev/null +++ b/foldhaus_search_lister.h @@ -0,0 +1,33 @@ +internal s32 +GetNextHotItem (s32 CurrentHotItem, s32 ListLength) +{ + s32 Result = GSMin(CurrentHotItem + 1, ListLength - 1); + return Result; +} + +internal s32 +GetPrevHotItem (s32 CurrentHotItem) +{ + s32 Result = GSMax(0, CurrentHotItem - 1); + return Result; +} + +FOLDHAUS_INPUT_COMMAND_PROC(SearchListerNextItem) +{ + State->GeneralPurposeSearchHotItem = GetNextHotItem(State->GeneralPurposeSearchHotItem, NodeSpecificationsCount); +} + +FOLDHAUS_INPUT_COMMAND_PROC(SearchListerPrevItem) +{ + State->GeneralPurposeSearchHotItem = GetPrevHotItem(State->GeneralPurposeSearchHotItem); +} + +FOLDHAUS_INPUT_COMMAND_PROC(CloseSearchLister) +{ + // TODO(Peter): This is to show the node list. Generalize to just a lister + State->InterfaceShowNodeList = false; + // TODO(Peter): This also assumes we know where we came from. Probably need to implement + // push/pop functionality for the activecommands. + State->ActiveCommands = &State->InputCommandRegistry; + State->GeneralPurposeSearchHotItem = -1; +} diff --git a/foldhaus_text_entry.cpp b/foldhaus_text_entry.cpp index c89d8d4..a0708e9 100644 --- a/foldhaus_text_entry.cpp +++ b/foldhaus_text_entry.cpp @@ -1,28 +1,60 @@ +internal void +ResetTextInput (text_input* Input) +{ + Input->CursorPosition = 0; + Input->Buffer.Length = 0; +} + +internal void +PipeSearchStringToDestination (text_input* Input) +{ + switch (Input->Destination.Type) + { + case TextTranslateTo_String: + { + CopyStringTo(Input->Buffer, Input->Destination.StringDest); + }break; + + case TextTranslateTo_R32: + { + parse_result FloatParseResult = ParseFloat(Input->Buffer.Memory, Input->Buffer.Length); + *Input->Destination.FloatDest = FloatParseResult.FloatValue; + }break; + + InvalidDefaultCase; + } +} + FOLDHAUS_INPUT_COMMAND_PROC(RemoveCharacterFromEntryString) { - if (State->GeneralPurposeSearch.CursorPosition > 0) + if (State->ActiveTextEntry.CursorPosition > 0) { - RemoveCharAt(&State->GeneralPurposeSearch.Buffer, - State->GeneralPurposeSearch.CursorPosition - 1); - State->GeneralPurposeSearch.CursorPosition--; + RemoveCharAt(&State->ActiveTextEntry.Buffer, + State->ActiveTextEntry.CursorPosition - 1); + State->ActiveTextEntry.CursorPosition--; } } internal void -ActivateTextEntry(text_input* ActiveEntryString, app_state* State) +SetTextInputDestinationToString (text_input* TextInput, string* DestinationString) { - State->ActiveTextEntry = ActiveEntryString; - State->ActiveTextEntry->PreviousCommandRegistry = State->ActiveCommands; - State->ActiveCommands = &State->TextEntryCommandRegistry; + ResetTextInput(TextInput); + TextInput->Destination.Type = TextTranslateTo_String; + TextInput->Destination.StringDest = DestinationString; + CopyStringTo(*DestinationString, &TextInput->Buffer); } -internal void -DeactivateTextEntry(app_state* State) +internal void +SetTextInputDestinationToFloat (text_input* TextInput, r32* DestinationFloat) { - if (State->ActiveTextEntry->PreviousCommandRegistry != 0) + ResetTextInput(TextInput); + TextInput->Destination.Type = TextTranslateTo_R32; + TextInput->Destination.FloatDest = DestinationFloat; + PrintF(&TextInput->Buffer, "%f", *DestinationFloat); + + if (*DestinationFloat == 0.0f) { - State->ActiveCommands = State->ActiveTextEntry->PreviousCommandRegistry; - State->ActiveTextEntry = 0; + TextInput->CursorPosition = 1; } } @@ -37,18 +69,25 @@ AppendInputToEntryString (text_input* EntryString, char* InputString, s32 InputS EntryString->CursorPosition++; } } + PipeSearchStringToDestination(EntryString); } FOLDHAUS_INPUT_COMMAND_PROC(TextEntryMoveCursorRight) { - State->ActiveTextEntry->CursorPosition = GSMin(State->ActiveTextEntry->Buffer.Length, - State->ActiveTextEntry->CursorPosition + 1); + State->ActiveTextEntry.CursorPosition = GSMin(State->ActiveTextEntry.Buffer.Length, + State->ActiveTextEntry.CursorPosition + 1); } FOLDHAUS_INPUT_COMMAND_PROC(TextEntryMoveCursorLeft) { - State->ActiveTextEntry->CursorPosition = GSMax(0, - State->ActiveTextEntry->CursorPosition - 1); + State->ActiveTextEntry.CursorPosition = GSMax(0, + State->ActiveTextEntry.CursorPosition - 1); +} + +FOLDHAUS_INPUT_COMMAND_PROC(LeaveTextEntryMode) +{ + // TODO(Peter): Make this more flexible. Should return to whatever came before + State->ActiveCommands = &State->InputCommandRegistry; } internal void @@ -59,5 +98,7 @@ InitializeTextInputCommands (input_command_registry* SearchCommands, memory_aren RegisterKeyPressCommand(SearchCommands, KeyCode_Backspace, false, KeyCode_Invalid, RemoveCharacterFromEntryString); RegisterKeyPressCommand(SearchCommands, KeyCode_LeftArrow, false, KeyCode_Invalid, TextEntryMoveCursorLeft); RegisterKeyPressCommand(SearchCommands, KeyCode_RightArrow, false, KeyCode_Invalid, TextEntryMoveCursorRight); + RegisterKeyPressCommand(SearchCommands, KeyCode_Enter, false, KeyCode_Invalid, + LeaveTextEntryMode); } } diff --git a/foldhaus_text_entry.h b/foldhaus_text_entry.h index eba56ff..6917d55 100644 --- a/foldhaus_text_entry.h +++ b/foldhaus_text_entry.h @@ -1,7 +1,26 @@ +enum text_translation_type +{ + TextTranslateTo_String, + TextTranslateTo_R32, + TextTranslateTo_S32, + TextTranslateTo_U32, +}; + +struct text_input_destination +{ + text_translation_type Type; + union { + string* StringDest; + r32* FloatDest; + s32* SignedIntDest; + u32* UnsignedIntDest; + }; +}; + struct text_input { - char* Backbuffer; string Buffer; s32 CursorPosition; - input_command_registry* PreviousCommandRegistry; + + text_input_destination Destination; }; \ No newline at end of file diff --git a/interface.h b/interface.h index d146dd2..61b0a0f 100644 --- a/interface.h +++ b/interface.h @@ -562,6 +562,7 @@ EvaluateColorPicker (render_command_buffer* RenderBuffer, v4* Value, v2 PanelMin struct search_lister_result { s32 HotItem; + s32 SelectedItem; b32 ShouldRemainOpen; }; @@ -578,17 +579,7 @@ EvaluateSearchLister (render_command_buffer* RenderBuffer, v2 TopLeft, v2 Dimens search_lister_result Result = {}; Result.ShouldRemainOpen = true; Result.HotItem = HotItem; - - // NOTE(Peter): These are direction reversed because going up the list in terms of indicies is - // visually displayed as going down. - if (KeyTransitionedDown(Input, KeyCode_DownArrow)) - { - Result.HotItem = GSMin(Result.HotItem + 1, ListLength - 1); - } - if (KeyTransitionedDown(Input, KeyCode_UpArrow)) - { - Result.HotItem = GSMax(0, Result.HotItem - 1); - } + Result.SelectedItem = -1; // Title Bar PushRenderQuad2D(RenderBuffer, v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}, v4{.3f, .3f, .3f, 1.f}); @@ -624,7 +615,7 @@ EvaluateSearchLister (render_command_buffer* RenderBuffer, v2 TopLeft, v2 Dimens Config.Font, Input); if (Button.Pressed) { - Result.HotItem = i; + Result.SelectedItem = i; } TopLeft.y -= 30; diff --git a/todo.txt b/todo.txt index 105d8c0..c52e111 100644 --- a/todo.txt +++ b/todo.txt @@ -4,9 +4,10 @@ Hardening - input context changes - x don't type into the search bar when its not open - x don't type into the search bar when you press a to open it -- - type into text boxes +- x type into text boxes - - shift drag to 10x drag speed - select nodes -> delete nodes +- open add node menu, click off to the side, it still adds a node. Name - Splash screen (like blender) (thisll be fun)