[英]Text input box in SDL
也許嘗試像這里提到的 nanogui-sdl 這樣的特定於 SDL 的庫
這是輸入小部件的代碼。
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
int windowWidth = 240;
int windowHeight = 320;
SDL_Point mousePos;
SDL_Point realMousePos;
bool keys[SDL_NUM_SCANCODES];
bool buttons[SDL_BUTTON_X2 + 1];
SDL_Renderer* renderer;
int SDL_QueryTextureF(SDL_Texture* texture, Uint32* format, int* access, float* w, float* h)
{
int wi, hi;
int result = SDL_QueryTexture(texture, format, access, &wi, &hi);
if (w) {
*w = wi;
}
if (h) {
*h = hi;
}
return result;
}
SDL_Texture* renderText(SDL_Texture* previousTexture, TTF_Font* font, SDL_Renderer* renderer, const std::string& text, SDL_Color color)
{
if (previousTexture) {
SDL_DestroyTexture(previousTexture);
}
SDL_Surface* surface;
if (text.empty()) {
surface = TTF_RenderUTF8_Blended(font, " ", color);
}
else {
surface = TTF_RenderUTF8_Blended(font, text.c_str(), color);
}
if (surface) {
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_FreeSurface(surface);
return texture;
}
else {
return 0;
}
}
struct Text {
std::string text;
SDL_Surface* surface = 0;
SDL_Texture* t = 0;
SDL_FRect dstR{};
bool autoAdjustW = false;
bool autoAdjustH = false;
float wMultiplier = 1;
float hMultiplier = 1;
~Text()
{
if (surface) {
SDL_FreeSurface(surface);
}
if (t) {
SDL_DestroyTexture(t);
}
}
Text()
{
}
Text(const Text& rightText)
{
text = rightText.text;
if (surface) {
SDL_FreeSurface(surface);
}
if (t) {
SDL_DestroyTexture(t);
}
if (rightText.surface) {
surface = SDL_ConvertSurface(rightText.surface, rightText.surface->format, SDL_SWSURFACE);
}
if (rightText.t) {
t = SDL_CreateTextureFromSurface(renderer, surface);
}
dstR = rightText.dstR;
autoAdjustW = rightText.autoAdjustW;
autoAdjustH = rightText.autoAdjustH;
wMultiplier = rightText.wMultiplier;
hMultiplier = rightText.hMultiplier;
}
Text& operator=(const Text& rightText)
{
text = rightText.text;
if (surface) {
SDL_FreeSurface(surface);
}
if (t) {
SDL_DestroyTexture(t);
}
if (rightText.surface) {
surface = SDL_ConvertSurface(rightText.surface, rightText.surface->format, SDL_SWSURFACE);
}
if (rightText.t) {
t = SDL_CreateTextureFromSurface(renderer, surface);
}
dstR = rightText.dstR;
autoAdjustW = rightText.autoAdjustW;
autoAdjustH = rightText.autoAdjustH;
wMultiplier = rightText.wMultiplier;
hMultiplier = rightText.hMultiplier;
return *this;
}
void setText(SDL_Renderer* renderer, TTF_Font* font, std::string text, SDL_Color c = { 255,255,255 })
{
this->text = text;
#if 1 // NOTE: renderText
if (surface) {
SDL_FreeSurface(surface);
}
if (t) {
SDL_DestroyTexture(t);
}
if (text.empty()) {
surface = TTF_RenderUTF8_Blended(font, " ", c);
}
else {
surface = TTF_RenderUTF8_Blended(font, text.c_str(), c);
}
if (surface) {
t = SDL_CreateTextureFromSurface(renderer, surface);
}
#endif
if (autoAdjustW) {
SDL_QueryTextureF(t, 0, 0, &dstR.w, 0);
}
if (autoAdjustH) {
SDL_QueryTextureF(t, 0, 0, 0, &dstR.h);
}
dstR.w *= wMultiplier;
dstR.h *= hMultiplier;
}
void setText(SDL_Renderer* renderer, TTF_Font* font, int value, SDL_Color c = { 255,255,255 })
{
setText(renderer, font, std::to_string(value), c);
}
void draw(SDL_Renderer* renderer)
{
if (t) {
SDL_RenderCopyF(renderer, t, 0, &dstR);
}
}
};
std::string ucs4ToUtf8(const std::u32string& in)
{
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> conv;
return conv.to_bytes(in);
}
std::u32string utf8ToUcs4(const std::string& in)
{
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> conv;
return conv.from_bytes(in);
}
void utf8Insert(std::string& buffer, int index, std::string text)
{
std::u32string u32Buffer = utf8ToUcs4(buffer);
if (index > u32Buffer.size()) {
index = u32Buffer.size();
}
u32Buffer.insert(index, utf8ToUcs4(text));
buffer = ucs4ToUtf8(u32Buffer);
}
std::string utf8Substr(const std::string& str, unsigned int start, unsigned int leng)
{
std::u32string s = utf8ToUcs4(str);
return ucs4ToUtf8(s.substr(start, leng));
}
std::size_t utf8GetSize(std::string buffer)
{
std::u32string str = utf8ToUcs4(buffer);
return str.size();
}
void utf8Erase(std::string& buffer, int index)
{
buffer = utf8Substr(buffer, 0, index) + utf8Substr(buffer, index + 1, std::string::npos);
}
struct Input {
SDL_Rect r{};
Text text;
SDL_Rect cursorR{};
int currentLetter = 0;
std::u32string left;
std::u32string right;
bool isPassword = false;
bool isSelected = false;
void handleEvent(SDL_Event event, TTF_Font* font)
{
if (event.type == SDL_KEYDOWN) {
if (event.key.keysym.scancode == SDL_SCANCODE_BACKSPACE) {
if (currentLetter) {
utf8Erase(text.text, currentLetter - 1);
if (!right.empty()) {
std::u32string s = utf8ToUcs4(text.text);
s.push_back(right.front());
right.erase(0, 1);
text.text = ucs4ToUtf8(s);
}
else if (!left.empty()) {
std::u32string s = utf8ToUcs4(text.text);
s.insert(0, 1, left.back());
left.pop_back();
text.text = ucs4ToUtf8(s);
}
else {
--currentLetter;
}
text.setText(renderer, font, text.text, {});
}
}
else if (event.key.keysym.scancode == SDL_SCANCODE_LEFT) {
if (currentLetter) {
--currentLetter;
}
else {
if (!left.empty()) {
std::u32string s = utf8ToUcs4(text.text);
s.insert(s.begin(), left.back());
left.pop_back();
right.insert(right.begin(), s.back());
s.pop_back();
text.setText(renderer, font, ucs4ToUtf8(s), {});
}
}
}
else if (event.key.keysym.scancode == SDL_SCANCODE_RIGHT) {
if (currentLetter != utf8ToUcs4(text.text).size()) {
++currentLetter;
}
else {
if (!right.empty()) {
std::u32string s = utf8ToUcs4(text.text);
s.push_back(right.front());
right.erase(0, 1);
left.push_back(s.front());
s.erase(0, 1);
text.setText(renderer, font, ucs4ToUtf8(s), {});
}
}
}
}
else if (event.type == SDL_TEXTINPUT) {
utf8Insert(text.text, currentLetter, event.text.text);
text.setText(renderer, font, text.text, {});
++currentLetter;
while (text.dstR.x + text.dstR.w > r.x + r.w) {
--currentLetter;
left.push_back(utf8ToUcs4(text.text)[0]);
utf8Erase(text.text, 0);
text.setText(renderer, font, text.text, {});
}
}
}
void draw(SDL_Renderer* renderer, TTF_Font* font)
{
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 0);
SDL_RenderFillRect(renderer, &r);
if (isPassword) {
std::string currPassword = text.text;
text.setText(renderer, font, std::string(utf8GetSize(currPassword), '*'), {});
text.draw(renderer);
text.setText(renderer, font, currPassword, {});
}
else {
text.draw(renderer);
}
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 0);
Text t = text;
t.text = utf8Substr(t.text, 0, currentLetter);
t.setText(renderer, font, t.text, {});
if (currentLetter) {
cursorR.x = t.dstR.x + t.dstR.w;
}
else {
cursorR.x = t.dstR.x;
}
if (isSelected) {
SDL_RenderFillRect(renderer, &cursorR);
}
}
};
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
TTF_Init();
SDL_Window* window = SDL_CreateWindow("TextEditInput", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowWidth, windowHeight, SDL_WINDOW_RESIZABLE);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
TTF_Font* robotoF = TTF_OpenFont("res/roboto.ttf", 72);
int w, h;
SDL_GetWindowSize(window, &w, &h);
SDL_RenderSetScale(renderer, w / (float)windowWidth, h / (float)windowHeight);
bool running = true;
Input input;
input.r.w = 200;
input.r.h = 30;
input.r.x = windowWidth / 2 - input.r.w / 2;
input.r.y = windowHeight / 2.f - input.r.h - 10;
input.text.dstR.w = input.r.w;
input.text.dstR.h = input.r.h;
input.text.dstR.x = input.r.x;
input.text.dstR.y = input.r.y;
input.text.autoAdjustW = true;
input.text.wMultiplier = 0.5;
input.cursorR.w = 8;
input.cursorR.h = input.r.h - 2;
input.cursorR.x = input.r.x;
input.cursorR.y = input.r.y + input.r.h / 2 - input.cursorR.h / 2;
input.isSelected = true;
while (running) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
input.handleEvent(event, robotoF);
if (event.type == SDL_QUIT || event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) {
running = false;
}
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
input.draw(renderer, robotoF);
SDL_RenderPresent(renderer);
}
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.