Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Growing a vector from InputTextMultiline #1443

Closed
ghost opened this issue Nov 16, 2017 · 4 comments
Closed

Growing a vector from InputTextMultiline #1443

ghost opened this issue Nov 16, 2017 · 4 comments

Comments

@ghost
Copy link

ghost commented Nov 16, 2017

I did search online but could not find anything about it and so I wanted to propose my solution to the problem.

Wait a minute, what am I talking about (O.o")? Let's start from the beginning ...

... Hi! ... oops I think I have gone too far back XD ... excuse me ... Let me retry ... I was playing with InputTextMultiline when I noticed that there is not an official way to use a dynamic-allocated buffer (e.g. vector) for text typing and so you need to specify the size that may be a limit like in my case.

I apologize in advance if I am wrong was not my intention to disturb you.

Below my solution,
I wanted it compatible with the official version so I had not to modify anything other than InputTextMultiline and InputTextEx.

InputTextEx

I added a pointer to the vector, as optional parameter, that will be used only in case you have not a defined size while maintaining the function compatible for all other calls.

bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data, ImVector<char>* v)

I could not know how many characters I would have to add without first filtering them so I push them into a temporary vector that will be used immediately afterwards to reallocate the two vectors. Next, I call OnKeyPressed to append the characters.

if (io.InputCharacters[0])
{
	// Process text input (before we check for Return because using some IME will effectively send a Return?)
	// We ignore CTRL inputs, but need to allow CTRL+ALT as some keyboards (e.g. German) use AltGR - which is Alt+Ctrl - to input certain characters.
	ImVector<int> filtered_input_characters;

	if (!(io.KeyCtrl && !io.KeyAlt) && is_editable)
	{
		for (int n = 0; n < IM_ARRAYSIZE(io.InputCharacters) && io.InputCharacters[n]; n++)
			if (unsigned int c = (unsigned int)io.InputCharacters[n])
			{
				if (!InputTextFilterCharacter(&c, flags, callback, user_data))
					continue;

				// Push the filtered character into a temporary vector for future use
				filtered_input_characters.push_back((int)c);
			}
	}

	// Check whether buf is referencing to v
	//		and make sure buf is the same as v->Data
	if (v && buf == v->Data)
	{
		// Increase buf_size for future use
		buf_size += filtered_input_characters.Size;

		// Resize both vectors to have enough space to contain the filtered characters
		edit_state.Text.resize(buf_size + 1);
		v->resize(edit_state.Text.Size);

		// Update BufSizeA
		edit_state.BufSizeA = buf_size;
	}

	// Handle key press
	for (int c : filtered_input_characters)
		edit_state.OnKeyPressed(c);

	memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
}

InputTextMultiline

I added a second definition of the InputTextMultiline function this time though using a vector. I check the vector size to make it safer to use by guaranteeing the validity of the pointer Data even if not initialized. I pass the vector address as last parameter.

bool ImGui::InputTextMultiline(const char* label, ImVector<char>& v, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
{
	if (v.Size < 1) // Make sure Data is a valid pointer
		v.push_back('\0'); // equivalent of v.resize(1); v.Data[0] = '\0';

	return InputTextEx(label, v.Data, v.Size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data, &v);
}

ImVector

I had to make the ImVector class visible to the InputTextMultiline function.

template<typename T>
class ImVector; // Needed for InputTextMultiline

// ImGui end-user API
// In a namespace so that user can add extra functions in a separate file (e.g. Value() helpers for your vector or common types)
namespace ImGui
{

I hope to have been helpful and thank all those who have contributed to realize this masterpiece.
I apologize for my english and I look forward to your opinion on this.

@ocornut ocornut changed the title InputTextMultiline Growing a vector from InputTextMultiline Nov 16, 2017
@ebachard
Copy link

@crylessdomore : very interesting feature. Thank you very much for sharing your code !

👍

@Flix01
Copy link

Flix01 commented Nov 16, 2017

@crylessdomore: Does this trick work when pasting code to it?

P.S. Good approach using an optional char vector as last parameter. 👍

@ghost
Copy link
Author

ghost commented Nov 16, 2017

@Flix01 I had not thought of that, thank you for letting me know. I see what I can do in the next few hours :)

--- EDIT ---

It seems working now ## but crash with a large clipboard text

// Paste
if (const char* clipboard = GetClipboardText())
{
	// Filter pasted buffer
	const int clipboard_len = (int)strlen(clipboard);
	ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len+1) * sizeof(ImWchar));
	int clipboard_filtered_len = 0;
	for (const char* s = clipboard; *s; )
	{
		unsigned int c;
		s += ImTextCharFromUtf8(&c, s, NULL);
		if (c == 0)
			break;
		if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, user_data))
			continue;
		clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
	}
	clipboard_filtered[clipboard_filtered_len] = 0;
	if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
	{
		// Check whether buf is referencing to v
		//		and make sure buf is the same as v->Data
		if (v && buf == v->Data)
		{
			// Increase buf_size for future use
			buf_size += clipboard_filtered_len;

			// Resize both vectors to have enough space to contain clipboard_filtered
			edit_state.Text.resize(buf_size + 1);
			v->resize(edit_state.Text.Size);

			// Update BufSizeA
			edit_state.BufSizeA = buf_size; // Needed for STB_TEXTEDIT_INSERTCHARS
		}

		stb_textedit_paste(&edit_state, &edit_state.StbState, clipboard_filtered, clipboard_filtered_len);
		edit_state.CursorFollow = true;
	}
	ImGui::MemFree(clipboard_filtered);
}

ocornut added a commit that referenced this issue Aug 22, 2018
ocornut added a commit that referenced this issue Aug 22, 2018
…(followup to 24ff259) + fixed demo to use those functions.  (#2006, #1443, #1008).
ocornut added a commit that referenced this issue Aug 22, 2018
@ocornut
Copy link
Owner

ocornut commented Aug 22, 2018

I have pushed a solution for this problem, described in #2006.
Closing this topic. feel free to comment in #2006 to state if it works for you or if you have other feedback.

@ocornut ocornut closed this as completed Aug 22, 2018
ocornut added a commit that referenced this issue Aug 22, 2018
…h Escape key. Avoid over-allocating for InitialText storage. (#2006, #1443, #1008)
ocornut added a commit that referenced this issue Aug 22, 2018
ocornut added a commit that referenced this issue Oct 12, 2018
ocornut added a commit that referenced this issue Mar 12, 2019
ocornut added a commit that referenced this issue Dec 25, 2019
ocornut added a commit that referenced this issue Feb 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants