Write a letter in InputField at Caret Position - unity3d

I have created some buttons in Unity. When a button is clicked a function is called to write text on an InputText component. The function is following for example:
public void JButton()
{
textshowed.text = textshowed.text + "J";
}
But if I want to write a letter in between a line, the word is written at last of line.
What should i do for the letter to written where the cursor/caret is?

note that it doesnt handle selections in InputField. Below might be enough for your purpose?
public class button : MonoBehaviour
{
public InputField myInput;
int caretposition;
public void JButton()
{
myInput.text = myInput.text.Insert(caretposition, "J");
//Debug.Log(myInput.caretPosition);
}
private void Update()
{
if (myInput.isFocused)
{
caretposition = myInput.caretPosition;
}
}
}

Related

How do i implement TMP in an unity script that normally supports unity text

I'm following a skillshare tutorial on how to make a card game, and in the tutorial normal unity text is used, but in for me the text turns out blurry. So i turned to using TextMeshPro to doing it because the text supports auto-resizing and is crisp.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
// holds the refs to all the Text, Images on the card
public class OneCardManager : MonoBehaviour {
public CardAsset cardAsset;
public OneCardManager PreviewManager;
[Header("Text Component References")]
public Text ManaCostText;
public Text PowerText;
[Header("Image References")]
public Image CardBodyImage;
public Image CardFaceGlowImage;
public Image CardBackGlowImage;
void Awake()
{
if (cardAsset != null)
ReadCardFromAsset();
}
private bool canBePlayedNow = false;
public bool CanBePlayedNow
{
get
{
return canBePlayedNow;
}
set
{
canBePlayedNow = value;
CardFaceGlowImage.enabled = value;
}
}
public void ReadCardFromAsset()
{
// universal actions for any Card
// add mana cost
ManaCostText.text = cardAsset.ManaCost.ToString();
if (cardAsset.Power != 0)
{
// this is a creature
PowerText.text = cardAsset.Power.ToString();
}
if (PreviewManager != null)
{
// this is a card and not a preview
// Preview GameObject will have OneCardManager as well, but PreviewManager should be null there
PreviewManager.cardAsset = cardAsset;
PreviewManager.ReadCardFromAsset();
}
}
}
the mana text should be able to take in a TMP object but i don't know how to do that. help please!
Use the TMPro.TMP_Text instead of UnityEngine.UI.Text.

Unity How to combine each object name?

I put several button and i linked onClick() each buttons.
It's okay to print each button name.
But when i click another button, The text didn't combine previous text...
========================================================
public Text showText; //print text
public int count = 0; // count how many times click button
public void ButtonClick_1()
{
Debug.Log("Button Clicked!");
print(gameObject.name);
if (count == 0) { showText.text = gameObject.name; }
else { showText.text += gameObject.name; }
count++;
}
==================================================
First
click button1 => it's okay to print " button1 "
Second
click button1 again => It's okay to print " button1button1"
Third
click button2 => It's not okay to print. print like "button2". I hope it print"button1button1button2"
==========================================================
I want to figure out this.....
I have to put several buttons so use tag is more useful?
I'm not used to use tag. Hope someone help me out.
So as I understood you have this script on multiple buttons.
You have a check on count which initially is 0 for each individual instance.
So instead you could make it static so it is "shared" between all instances or better said makes it a static class member which is not related to any instance.
public Text showText;
public static int count = 0;
public void ButtonClick_1()
{
Debug.Log("Button Clicked!");
print(gameObject.name);
if (count == 0)
{
showText.text = gameObject.name;
}
else
{
showText.text += gameObject.name;
}
count++;
}
So that the text is only overwritten by the very first button click.
Your comment
Actually i print like "000" ,"001",,"012","123".
sounds like you actually want to print always the last three buttons.
I would rather use e.g. a static List<string> like
private static List<string> lastThreeButtons = new List<string>();
public void ButtonClick()
{
lastThreeButtons.Add(name);
if(lastThreeButtons.Count == 3)
{
showText.text = lastThreeButtons[0] + lastThreeButtons[1] + lastThreeButtons[3];
lastThreeButtons.Clear();
}
}
This is how I would do it :
Have a singleton class :
public class TextManager : MonoBehaviour
{
public static TextManager Instance;
public UnityEngine.UI.Text myUIText;
private void Awake()
{
Instance = this;
}
public void AddLine(string _line)
{
myUIText.text += $"{_line} \n";
}
}
Put this Component on a GameObject and link the UIText in the inspector
Then on my ButtonScript I would have this :
public void ButtonClick()
{
Debug.Log($"{gameObject.name} Clicked!");
TextManager.Instance.AddLine(gameObject.name);
}

can the ui.inputfield have the data from both text box and input displayed overlaying each other?

I have a Unity Droid app with an ui.inputfield. I am giving the user the ability to enter numbers or move a slider. In either case I need to have the slider data appear in the inputfield or update the slider position with the number typed into the inputfield. I can get the data from both the inputfield or the slider but I need to have the data displayed. My main concern is can I have the data from both inputs displayed at the exact same location as the inputfield, like on top?
I can not find any examples of the data display on top of the input field. Is this the correct way to think about this?
Thank you in advance.
There are callbacks whenever the user changes a UI.Slider or finishes entering a value in a UI.InputField:
UI.Slider.onValueChanged
UI.InputField.onEndEdit
So yes you could link them to each other like e.g.
public class Example : MonoBehaviour
{
public InputField inputField;
public Slider slider;
private void Awake()
{
inputField.onEndEdit.AddListener(OnInputFieldChanged);
slider.onValueChanged .AddListener( OnSliderChanged);
OnSliderChanged(slider.value);
}
private void OnInputFieldChanged(string newText)
{
if (float.TryParse(newText, out var value))
{
value = Mathf.Clamp(value, slider.minValue, slider.maxValue);
inputField.text = value.ToString("F");
slider.value = value;
}
else
{
Debug.LogWarning("Input Format Error!", this);
slider.value = Mathf.Clamp(0, slider.minValue, slider.maxValue);
inputField.text = slider.value.ToString("F");
}
}
private void OnSliderChanged(float newValue)
{
inputField.text = newValue.ToString("F");
}
}

custom inspector not drawing correctly

GameContainer script:
public class GameContainer : MonoBehaviour
{
public List<Game> Games;
public void AddGame()
{
Games.Add(new Game());
}
}
Game Class:
[System.Serializable]
public class Game
{
public List<GameType> gameTypes;
public void addGameType()
{
gameTypes.Add(new GameType());
}
}
GameType Class
[System.Serializable]
public class GameType
{
}
and my OnInspectorGUI method in custom editor
public override void OnInspectorGUI()
{
var targetScript = target as GameContainer;
var centeredStyle = GUI.skin.GetStyle("Label");
centeredStyle.alignment = TextAnchor.UpperCenter;
centeredStyle.fontStyle = FontStyle.Bold;
EditorGUILayout.LabelField("Games", centeredStyle);
for(int i = 0;i<targetScript.Games.Count; i++)
{
Game game = targetScript.Games[i];
//here is the LINE CAUSING A PROBLEM
Debug.Log(game.gameTypes.Count);
GUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.Space();
GUILayout.BeginVertical("Game Types", "window");
if (GUILayout.Button("+"))
{
game.addGameType();
}
GUILayout.EndVertical();
GUILayout.EndVertical();
EditorGUILayout.Space();
}
if (GUILayout.Button("+"))
{
targetScript.AddGame();
}
}
the problem is with this line:
//here is the LINE CAUSING A PROBLEM
Debug.Log(game.gameTypes.Count);
when i hit AddGame Button, all draw calls after this line will be ignored for newly added element and its not shown till next change in code and refresh in the editor, if i remove this line, everything works just fine.
but if i try to use gameType list by any mean, it will not show correct view in inspector.
what the problem is?
I recommend using EditorGUILayout instead of old GUILayout class.
here's link to document for it:
https://docs.unity3d.com/ScriptReference/EditorGUILayout.html
Although unity introduced a new way to make custom editors lately that is called UI Elements.
You can create your own editors with layered architecture with xml,css like language.
here's some useful YouTube links for you:
https://www.youtube.com/watch?v=sVEmJ5-dr5E
https://www.youtube.com/watch?v=MNNURw0LeoQ
https://www.youtube.com/watch?v=GSRVI1HqlF4
And lastly you can check this beautiful editor attributes too:
https://github.com/dbrizov/NaughtyAttributes

How to focus inputfields while click on 'Tab' button in unity 3d

I want focus input fields using tab button. I have found some code for focusing input fields but that one not satisfied my requirement. In my application one page design like number of input field in both horizontal and vertical formate. In my page have 3 rows of input field and each row have 3 input fields. my requirement is when user click on tab button focus next input field it's working but when reach end of the row, how can I focus next row contain input field. Please suggest any idea. Thank you. You can find my sample page design in below.
Here is the code I have tried.
Selectable next = system.currentSelectedGameObject.GetComponent<Selectable().FindSelectableOnRight();
if (next != null)
{
InputField inputfield = next.GetComponent<InputField>();
if (inputfield != null)
{
inputfield.OnPointerClick(new PointerEventData(system));
system.SetSelectedGameObject(next.gameObject, new BaseEventData(system));
}
}
I had implemented the a similar function by NGUI, you can make some modify if using UGUI. The idea is set the nextInput manually by public variable
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIInputTab : MonoBehaviour {
UIInput thisInput;
public GameObject nextInput;
void Start () {
thisInput = transform.GetComponent<UIInput>();
}
void Update () {
if (thisInput.isSelected)
{
if (nextInput != null && Input.GetKeyDown(KeyCode.Tab))
{
UICamera.selectedObject = nextInput;
}
}
}
}
Update
: Dynamic generate random number InputField and assign the next InputField.
InputfieldTest.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class InputfieldTest : MonoBehaviour {
public GameObject inputFieldPrefab;
public GameObject panel;
private GameObject lastInput;
EventSystem m_EventSystem;
void Start () {
m_EventSystem = EventSystem.current;
for(int i = 0; i < Random.Range(5,10);i++){
GameObject column = new GameObject();
column.transform.parent = panel.transform;
column.name = "Column" + i;
for (int j = 0; j < Random.Range(2, 8);j++){
GameObject input = Instantiate(inputFieldPrefab);
input.transform.parent = column.transform;
input.GetComponent<RectTransform>().position = new Vector3(300+ 200 * j, 300+ 200 * i, 0);
input.name = "InputField" + i + "-" + j;
// set nextInput
if(lastInput != null) {
lastInput.GetComponent<InputTabControl>().nextInput = input;
}
lastInput = input;
}
}
}
void Update () {
GameObject currentSelect = m_EventSystem.currentSelectedGameObject;
if (currentSelect != null)
{
print(currentSelect.name);
GameObject nextInput = currentSelect.GetComponent<InputTabControl>().nextInput;
if (nextInput != null && Input.GetKeyDown(KeyCode.Tab))
{
InputField inputfield = nextInput.GetComponent<InputField>();
if (inputfield != null)
{
inputfield.OnPointerClick(new PointerEventData(m_EventSystem));
m_EventSystem.SetSelectedGameObject(nextInput.gameObject, new BaseEventData(m_EventSystem));
}
}
}
}
}
InputTabControl.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InputTabControl : MonoBehaviour {
public GameObject nextInput;
}
Result:
Here's my solution, pretty similar.
public class TabToNextController : MonoBehaviour {
public InputField nextField;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (GetComponent<InputField> ().isFocused && Input.GetKeyDown (KeyCode.Tab)) {
nextField.ActivateInputField ();
}
}
Just add this script to the item you want to be tabbed from. Then in the GUI drop in the inputfield you want to be tabbed to as the "nextField".
I recently ran into this problem and it drove me crazy to think there was no tabs feature. I had never noticed it before. A simple solution that seems to work so far is to use the Selectable class that the UI elements inherit from.
I tested this with the most common types (for me) - InputField, Buttons and drop down lists.
It tabs to each of them as expected
use spacebar to click the button
use spacebar to open the drop down
If you want full web style controls (eg arrow keys) to invoke the drop down, you need to write that code.
public class TabToNextController : MonoBehaviour, IUpdateSelectedHandler
{
public Selectable nextField;
public void OnUpdateSelected(BaseEventData data)
{
if (Input.GetKeyDown(KeyCode.Tab))
nextField.Select();
}
}
Cheers
This is what worked for me:
public Selectable next; //if you want the cursor to start at a specific field
//you can set this in the inspector to any input field
private EventSystem system;
private int tabIndex; //to keep track of cursor
void Start()
{
system = EventSystem.current;// EventSystemManager.currentSystem;
//if you don't want to set next in the inspector, you can do it here
//next = Selectable.allSelectables[0];
tabIndex = 0;
next.Select(); //make sure to do this!
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Tab))
{
if (tabIndex >= Selectable.allSelectables.Count)
{
next = Selectable.allSelectables[0];
tabIndex = 0;
}
else
{
//if nothing is selected then system.currentSelectedGameObject
//will throw a nullPointer Exception
next = system.currentSelectedGameObject.GetComponent<Selectable>()
.FindSelectableOnDown();
tabIndex++;
}
Debug.Log(next);
if (next != null)
{
InputField inputfield = next.GetComponent<InputField>();
if (inputfield != null)
inputfield.OnPointerClick(new PointerEventData(system)); //if it's an input field, also set the text caret
system.SetSelectedGameObject(next.gameObject, new BaseEventData(system));
}
}
}