Step-by-Step SDL Basic UI Controls: UITextEdit (2)

1. Introduction

In the previous article, we implemented some of the basic functionalities of UITextEdit. In this part, we’ll continue by implementing features like IME (Input Method Editor) support, along with copy, paste, and cut functionality.

2. Functional Requirements Analysis

Core Features

  • Copy, cut, and paste
  • IME support (for Chinese, Japanese, and other languages)

Interaction Details

To handle button events, we’ll check for user input in the bool Handle(SDL_Event*e) method. If a user presses Ctrl+C, we’ll store the selected content in the system clipboard. A crucial detail to note here is that after handling a key combination event, we need to prevent the C key from being processed as regular input. Other key combinations should be handled in a similar way.

For drawing the IME-related window, which is usually on top of other UI elements, we can’t handle it within the normal control drawing logic. Instead, it needs to be drawn at a lower level to ensure it’s rendered at the correct time. For this, we’ll choose to draw it within the SceneManager.

3. Essential SDL Functions

  • SDL_StartTextInput / SDL_StopTextInput: Enable/disable text input.
  • SDL_TEXTINPUT: A character input event.
  • SDL_TEXTEDITING: An input method editing event.
  • SDL_KEYDOWN: Used to detect key combinations like Ctrl+C, Ctrl+V, and Ctrl+X.
  • SDL_SetClipboardText / SDL_GetClipboardText: For clipboard operations.

4. Design Considerations

Paste, Copy, and Cut

  • Copy: Use SDL_SetClipboardText to save the selected text to the clipboard.
  • Paste: Use SDL_GetClipboardText to retrieve text from the clipboard.
  • Cut: This is a combination of copying the selected text and then deleting it.

IME Support

  • To input characters from Eurasian languages like Chinese or Japanese, you need the appropriate font support.
  • The SDL_TEXTEDITING event provides the temporary input string and cursor position.
  • You must render this temporary input string at the cursor’s location.
  • Use platform-specific APIs to get the list of available IMEs.
  • Pay close attention to character encoding settings in different states.

5. Key Code Snippets

In the UITextEdit::Handle method:

C++

SDL_Keymod modState = SDL_GetModState();

switch (e->key.keysym.sym)
{
case SDLK_c:
{
	if (modState & KMOD_CTRL)
	{
		auto str = GetSelectionText();
		SDL_SetClipboardText(str.c_str());
		return true;
	}
	break;
}
case SDLK_v:
{
	if (modState & KMOD_CTRL)
	{
		auto str = SDL_GetClipboardText();
		replaceSelectionText(str);
		return true;
	}
	break;
}
case SDLK_x:
{
	if (modState & KMOD_CTRL)
	{
		auto str = GetSelectionText();
		SDL_SetClipboardText(str.c_str());
		removeSelectedText();
		return true;
	}
	break;
}

For drawing the IME list:

C++

void UITextEdit::DrawImgList()
{
	if (IsPassword()) return;
	if (m_ims.size() <= 0) return;
	SDL_Color bk{ 220,220,220,255 };
	SDL_Color clr{ 0,0,0,255 };
	SDL_Color csel{ 116,216,255,255 };
	int imesize = (int)(IME_SIZE);
	auto rc = calcCursorRect(cursor.position);
	auto [cw, ch] = sRender->GetClientSize();
	auto [w, h] = sRender->GetTextSize(wstring_to_utf8(m_ims[0]).c_str(), m_fontSize);
	int x = rc.x;
	int y = rc.y + rc.h;
	if (y + h * 8 > ch)
	{
		auto rect = GetGlobalRect();
		y = rect.y - (h + 4) * 8;
	}

	auto rcBK = SDL_Rect{ rc.x,y, 90, (h + 4) * imesize };
	sRender->FillRect(rcBK, bk);

	for (size_t i = 0; i < imesize; i++)
	{
		if (i == editing.index)
		{
			sRender->FillRect(SDL_Rect{ x,y,80, h + 4 }, csel);
		}
		SDL_Point pt{ x + 4,y + 2 };
		char txt[64] = {};
		//sprintf_s(txt, "%d. %s", (int)i + 1, wstring_to_utf8(m_ims[i]).c_str());
		sRender->DrawString(txt, m_fontSize, pt, clr);
		y += (h + 4);
	}
}

6. Example Usage

We’ll continue to use the same use case from the previous section.


7. Conclusion

In this article, we’ve enhanced the UITextEdit control by adding copy, paste, cut, and IME-related functionalities. In the next part, we’ll move on to implementing a UICheckBox.

Leave a Reply